kismet-2013-03-R1b/0000775000175000017500000000000012130551127013450 5ustar dragorndragornkismet-2013-03-R1b/endian_magic.h0000664000175000017500000001236212124602454016226 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ENDIAN_MAGIC_H__ #define __ENDIAN_MAGIC_H__ #include "config.h" // Byteswap magic #ifdef WORDS_BIGENDIAN #define kis_hton16(x) (x) #define kis_ntoh16(x) (x) #define kis_hton32(x) (x) #define kis_ntoh32(x) (x) #define kis_hton64(x) (x) #define kis_ntoh64(x) (x) #define kis_extract16(x) kis_extractBE16(x) #define kis_extract32(x) kis_extractBE32(x) #define kis_extract64(x) kis_extractBE64(x) #define kis_letoh16(x) kis_swap16((x)) #define kis_betoh16(x) (x) #define kis_letoh32(x) kis_swap32((x)) #define kis_betoh32(x) (x) #define kis_htole16(x) kis_swap16((x)) #define kis_htobe16(x) (x) #define kis_htobe32(x) (x) #define kis_htole32(x) kis_swap32((x)) #define kis_htobe64(x) (x) #define kis_htole64(x) kis_swap64((x)) #else #define kis_hton16(x) kis_swap16((x)) #define kis_ntoh16(x) kis_swap16((x)) #define kis_hton32(x) kis_swap32((x)) #define kis_ntoh32(x) kis_swap32((x)) #define kis_hton64(x) kis_swap64((x)) #define kis_ntoh64(x) kis_swap64((x)) #define kis_extract16(x) kis_extractLE16(x) #define kis_extract32(x) kis_extractLE32(x) #define kis_extract64(x) kis_extractLE64(x) #define kis_betoh16(x) kis_swap16((x)) #define kis_letoh16(x) (x) #define kis_betoh32(x) kis_swap32((x)) #define kis_letoh32(x) (x) #define kis_htole16(x) (x) #define kis_htobe16(x) kis_swap16((x)) #define kis_htole32(x) (x) #define kis_htobe32(x) kis_swap32((x)) #define kis_htole64(x) (x) #define kis_htobe64(x) kis_swap64((x)) #endif // Swap magic #define kis_swap16(x) \ ({ \ uint16_t __x = (x); \ ((uint16_t)( \ (uint16_t)(((uint16_t)(__x) & (uint16_t)0x00ff) << 8) | \ (uint16_t)(((uint16_t)(__x) & (uint16_t)0xff00) >> 8) )); \ }) #define kis_swap32(x) \ ({ \ uint32_t __x = (x); \ ((uint32_t)( \ (uint32_t)(((uint32_t)(__x) & (uint32_t)0x000000ff) << 24) | \ (uint32_t)(((uint32_t)(__x) & (uint32_t)0x0000ff00) << 8) | \ (uint32_t)(((uint32_t)(__x) & (uint32_t)0x00ff0000) >> 8) | \ (uint32_t)(((uint32_t)(__x) & (uint32_t)0xff000000) >> 24) )); \ }) #define kis_swap64(x) \ ({ \ uint64_t __x = (x); \ ((uint64_t)( \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ }) // Extract magic, also cribbed from tcpdump/ethereal #define kis_extractLE16(x) \ ((uint16_t)((uint16_t)*((const uint8_t *)(x) + 1) << 8 | \ (uint16_t)*((const uint8_t *)(x) + 0))) #define kis_extractLE32(x) \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 1) << 24 | \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 0) << 16 | \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 3) << 8 | \ (uint32_t)*((const uint8_t *)(x) + 2))) #define kis_extractLE64(x) \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 1) << 56 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 0) << 48 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 3) << 40 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 2) << 32 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 5) << 24 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 4) << 16 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 7) << 8 | \ (uint64_t)*((const uint8_t *)(x) + 6))) #define kis_extractBE16(x) \ ((uint16_t)((uint16_t)*((const uint8_t *)(x) + 0) << 8 | \ (uint16_t)*((const uint8_t *)(x) + 1))) #define kis_extractBE32(x) \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 0) << 24 | \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 1) << 16 | \ ((uint32_t)((uint32_t)*((const uint8_t *)(x) + 2) << 8 | \ (uint32_t)*((const uint8_t *)(x) + 3))) #define kis_extractBE64(x) \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 0) << 56 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 1) << 48 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 2) << 40 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 3) << 32 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 4) << 24 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 5) << 16 | \ ((uint64_t)((uint64_t)*((const uint8_t *)(x) + 6) << 8 | \ (uint64_t)*((const uint8_t *)(x) + 7))) #endif kismet-2013-03-R1b/darwin_control_wrapper.h0000664000175000017500000000246212124602454020414 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DARWIN_CONTROL_OBJC_H__ #define __DARWIN_CONTROL_OBJC_H__ #include "config.h" #ifdef SYS_DARWIN int darwin_bcom_testmonitor(); int darwin_bcom_enablemonitorfile(const char *c_filename); int darwin_bcom_enablemonitor(); void *darwin_allocate_interface(const char *in_iface); void darwin_free_interface(void *in_darwin); int darwin_get_channels(const char *in_iface, int **ret_channels); int darwin_set_channel(unsigned int in_channel, char *ret_err, void *in_darwin); void darwin_disassociate(void *in_darwin); int darwin_get_corewifi(void *in_darwin); #endif #endif kismet-2013-03-R1b/devicetracker.cc0000664000175000017500000003442612124602454016606 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "util.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "devicetracker.h" #include "packet.h" #include "gpsdclient.h" #include "alertracker.h" #include "manuf.h" #include "packetsource.h" enum KISDEV_COMMON_FIELDS { KISDEV_phytype, KISDEV_macaddr, KISDEV_firsttime, KISDEV_lasttime, KISDEV_packets, KISDEV_llcpackets, KISDEV_errorpackets, KISDEV_datapackets, KISDEV_cryptpackets, KISDEV_datasize, KISDEV_newpackets, KISDEV_channel, KISDEV_frequency, KISDEV_freqmhz, KISDEV_gpsfixed, KISDEV_minlat, KISDEV_minlon, KISDEV_minalt, KISDEV_minspd, KISDEV_maxlat, KISDEV_maxlon, KISDEV_maxalt, KISDEV_maxspd, KISDEV_signaldbm, KISDEV_noisedbm, KISDEV_minsignaldbm, KISDEV_minnoisedbm, KISDEV_maxsignaldbm, KISDEV_maxnoisedbm, KISDEV_signalrssi, KISDEV_noiserssi, KISDEV_minsignalrssi, KISDEV_minnoiserssi, KISDEV_maxsignalrssi, KISDEV_maxnoiserssi, KISDEV_bestlat, KISDEV_bestlon, KISDEV_bestalt, KISDEV_agglat, KISDEV_agglon, KISDEV_aggalt, KISDEV_aggpoints, KISDEV_maxfield }; const char *KISDEV_common_text[] = { "phytype", "macaddr", "firsttime", "lasttime", "packets", "llcpackets", "errorpackets", "datapackets", "cryptpackets", "datasize", "newpackets", "channel", "frequency", "freqmhz", "gpsfixed", "minlat", "minlon", "minalt", "minspd", "maxlat", "maxlon", "maxalt", "maxspd", "signaldbm", "noisedbm", "minsignaldbm", "minnoisedbm", "signalrssi", "noiserssi", "minsignalrssi", "minnoiserssi", "maxsignalrssi", "maxnoiserssi", "bestlat", "bestlon", "bestalt", "agglat", "agglon", "aggalt", "aggpoints", NULL }; enum DEVTAG_FIELDS { DEVTAG_macaddr, DEVTAG_tag, DEVTAG_value, DEVTAG_maxfield }; const char *DEVTAG_fields_text[] = { "macaddr", "tag", "value", NULL }; // Replaces the *INFO sentence enum TRACKINFO_FIELDS { TRACKINFO_devices, TRACKINFO_packets, TRACKINFO_datapackets, TRACKINFO_cryptpackets, TRACKINFO_errorpackets, TRACKINFO_filterpackets, TRACKINFO_packetrate, TRACKINFO_maxfield }; const char *TRACKINFO_fields_text[] = { "devices", "packets", "datapackets", "cryptpackets", "errorpackets", "filterpackets", "packetrate", NULL }; int Protocol_KISDEV_COMMON(PROTO_PARMS) { kis_device_common *com = (kis_device_common *) data; kis_tracked_device *dev = com->device; string scratch; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum > KISDEV_maxfield) { out_string = "\001Unknown field\001"; return -1; } if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } scratch = ""; switch (fnum) { case KISDEV_phytype: scratch = IntToString(com->phy_type); break; case KISDEV_macaddr: scratch = dev->key.Mac2String(); break; case KISDEV_firsttime: scratch = IntToString(com->first_time); break; case KISDEV_lasttime: scratch = IntToString(com->last_time); break; case KISDEV_packets: scratch = IntToString(com->packets); break; case KISDEV_llcpackets: scratch = IntToString(com->llc_packets); break; case KISDEV_errorpackets: scratch = IntToString(com->error_packets); break; case KISDEV_datapackets: scratch = IntToString(com->data_packets); break; case KISDEV_cryptpackets: scratch = IntToString(com->crypt_packets); break; case KISDEV_datasize: scratch = LongIntToString(com->datasize); break; case KISDEV_newpackets: scratch = IntToString(com->new_packets); break; case KISDEV_channel: scratch = IntToString(com->channel); break; case KISDEV_frequency: scratch = IntToString(com->frequency); break; case KISDEV_freqmhz: for (map::const_iterator fmi = com->freq_mhz_map.begin(); fmi != com->freq_mhz_map.end(); ++fmi) { scratch += IntToString(fmi->first) + ":" + IntToString(fmi->second) + "*"; } break; case KISDEV_gpsfixed: scratch = IntToString(com->gpsdata.gps_valid); break; case KISDEV_minlat: scratch = FloatToString(com->gpsdata.min_lat); break; case KISDEV_minlon: scratch = FloatToString(com->gpsdata.min_lon); break; case KISDEV_minalt: scratch = FloatToString(com->gpsdata.min_alt); break; case KISDEV_minspd: scratch = FloatToString(com->gpsdata.min_spd); break; case KISDEV_maxlat: scratch = FloatToString(com->gpsdata.max_lat); break; case KISDEV_maxlon: scratch = FloatToString(com->gpsdata.max_lon); break; case KISDEV_maxalt: scratch = FloatToString(com->gpsdata.max_alt); break; case KISDEV_maxspd: scratch = FloatToString(com->gpsdata.max_spd); break; case KISDEV_signaldbm: scratch = IntToString(com->snrdata.last_signal_dbm); break; case KISDEV_noisedbm: scratch = IntToString(com->snrdata.last_noise_dbm); break; case KISDEV_minsignaldbm: scratch = IntToString(com->snrdata.min_signal_dbm); break; case KISDEV_maxsignaldbm: scratch = IntToString(com->snrdata.max_signal_dbm); break; case KISDEV_minnoisedbm: scratch = IntToString(com->snrdata.min_noise_dbm); break; case KISDEV_maxnoisedbm: scratch = IntToString(com->snrdata.max_noise_dbm); break; case KISDEV_signalrssi: scratch = IntToString(com->snrdata.last_signal_rssi); break; case KISDEV_noiserssi: scratch = IntToString(com->snrdata.last_noise_rssi); break; case KISDEV_minsignalrssi: scratch = IntToString(com->snrdata.min_signal_rssi); break; case KISDEV_maxsignalrssi: scratch = IntToString(com->snrdata.max_signal_rssi); break; case KISDEV_minnoiserssi: scratch = IntToString(com->snrdata.min_noise_rssi); break; case KISDEV_maxnoiserssi: scratch = IntToString(com->snrdata.max_noise_rssi); break; case KISDEV_bestlat: scratch = IntToString(com->snrdata.peak_lat); break; case KISDEV_bestlon: scratch = IntToString(com->snrdata.peak_lon); break; case KISDEV_bestalt: scratch = IntToString(com->snrdata.peak_alt); break; case KISDEV_agglat: scratch = LongIntToString(com->gpsdata.aggregate_lat); break; case KISDEV_agglon: scratch = LongIntToString(com->gpsdata.aggregate_lon); break; case KISDEV_aggalt: scratch = LongIntToString(com->gpsdata.aggregate_alt); break; case KISDEV_aggpoints: scratch = LongIntToString(com->gpsdata.aggregate_points); break; } cache->Cache(fnum, scratch); out_string += scratch + " "; } return 1; } void Protocol_KISDEV_COMMON_enable(PROTO_ENABLE_PARMS) { ((Devicetracker *) data)->BlitDevices(in_fd); } int Protocol_KISDEV_TRACKINFO(PROTO_PARMS) { Devicetracker *tracker = (Devicetracker *) data; string scratch; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum > TRACKINFO_maxfield) { out_string = "\001Unknown field\001"; return -1; } if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } scratch = ""; switch (fnum) { case TRACKINFO_devices: scratch = IntToString(tracker->FetchNumDevices(KIS_PHY_ANY)); break; case TRACKINFO_packets: scratch = IntToString(tracker->FetchNumPackets(KIS_PHY_ANY)); break; case TRACKINFO_datapackets: scratch = IntToString(tracker->FetchNumDatapackets(KIS_PHY_ANY)); break; case TRACKINFO_cryptpackets: scratch = IntToString(tracker->FetchNumCryptpackets(KIS_PHY_ANY)); break; case TRACKINFO_errorpackets: scratch = IntToString(tracker->FetchNumErrorpackets(KIS_PHY_ANY)); break; case TRACKINFO_filterpackets: scratch = IntToString(tracker->FetchNumFilterpackets(KIS_PHY_ANY)); break; case TRACKINFO_packetrate: scratch = IntToString(tracker->FetchPacketRate(KIS_PHY_ANY)); break; } cache->Cache(fnum, scratch); out_string += scratch + " "; } return 1; } int Devicetracker_Timer(TIMEEVENT_PARMS) { return ((Devicetracker *) parm)->TimerKick(); } Devicetracker::Devicetracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; next_componentid = 0; num_packets = num_errorpackets = num_filterpackets = num_packetdelta = 0; conf_save = 0; next_phy_id = 0; // Internally register our common reference first devcomp_ref_common = RegisterDeviceComponent("COMMON"); // Timer kickoff timerid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &Devicetracker_Timer, this); // Register the tracked device component of packets _PCM(PACK_COMP_DEVICE) = globalreg->packetchain->RegisterPacketComponent("tracked_device"); // Register the network protocols proto_ref_commondevice = globalreg->kisnetserver->RegisterProtocol("COMMON", 0, 1, KISDEV_common_text, &Protocol_KISDEV_COMMON, &Protocol_KISDEV_COMMON_enable, this); proto_ref_trackinfo = globalreg->kisnetserver->RegisterProtocol("TRACKINFO", 0, 1, TRACKINFO_fields_text, &Protocol_KISDEV_TRACKINFO, NULL, this); } Devicetracker::~Devicetracker() { if (timerid >= 0) globalreg->timetracker->RemoveTimer(timerid); } void Devicetracker::SaveTags() { int ret; string dir = tag_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir"), "", "", 0, 1); ret = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); if (ret < 0 && errno != EEXIST) { string err = string(strerror(errno)); _MSG("Failed to create Kismet settings directory " + dir + ": " + err, MSGFLAG_ERROR); } ret = tag_conf->SaveConfig(tag_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir") + "/" + "tag.conf", "", "", 0, 1).c_str()); if (ret < 0) _MSG("Could not save tags, check previous error messages (probably " "no permission to write to the Kismet config directory: " + dir, MSGFLAG_ERROR); } int Devicetracker::FetchNumDevices(int in_phy) { int r = 0; if (in_phy == KIS_PHY_ANY) return tracked_map.size(); for (unsigned int x = 0; x < tracked_vec.size(); x++) { if (tracked_vec[x]->phy_type == in_phy) r++; } return r; } int Devicetracker::FetchNumPackets(int in_phy) { if (in_phy == KIS_PHY_ANY) return num_packets; map::iterator i = phy_packets.find(in_phy); if (i != phy_packets.end()) return i->second; return 0; } int Devicetracker::FetchNumDatapackets(int in_phy) { int r = 0; kis_device_common *common; for (unsigned int x = 0; x < tracked_vec.size(); x++) { if (tracked_vec[x]->phy_type == in_phy || in_phy == KIS_PHY_ANY) { if ((common = (kis_device_common *) tracked_vec[x]->fetch(devcomp_ref_common)) != NULL) r += common->data_packets; } } return 0; } int Devicetracker::FetchNumCryptpackets(int in_phy) { int r = 0; kis_device_common *common; for (unsigned int x = 0; x < tracked_vec.size(); x++) { if (tracked_vec[x]->phy_type == in_phy || in_phy == KIS_PHY_ANY) { if ((common = (kis_device_common *) tracked_vec[x]->fetch(devcomp_ref_common)) != NULL) r += common->crypt_packets; } } return 0; } int Devicetracker::FetchNumErrorpackets(int in_phy) { if (in_phy == KIS_PHY_ANY) return num_errorpackets; map::iterator i = phy_errorpackets.find(in_phy); if (i != phy_errorpackets.end()) return i->second; return 0; } int Devicetracker::FetchNumFilterpackets(int in_phy) { if (in_phy == KIS_PHY_ANY) return num_filterpackets; map::iterator i = phy_filterpackets.find(in_phy); if (i != phy_errorpackets.end()) return i->second; return 0; } int Devicetracker::FetchPacketRate(int in_phy) { if (in_phy == KIS_PHY_ANY) return num_packetdelta; map::iterator i = phy_packetdelta.find(in_phy); if (i != phy_packetdelta.end()) return i->second; return 0; } int Devicetracker::RegisterDeviceComponent(string in_component) { if (component_str_map.find(StrLower(in_component)) != component_str_map.end()) { return component_str_map[StrLower(in_component)]; } int num = next_componentid++; component_str_map[StrLower(in_component)] = num; component_id_map[num] = StrLower(in_component); return num; } int Devicetracker::RegisterPhyHandler(Kis_Phy_Handler *in_weak_handler) { int num = next_phy_id++; Kis_Phy_Handler *strongphy = in_weak_handler->CreatePhyHandler(globalreg, this, num); phy_handler_map[num] = strongphy; return num; } // Send all devices to a client void Devicetracker::BlitDevices(int in_fd) { for (unsigned int x = 0; x < tracked_vec.size(); x++) { kis_protocol_cache cache; // If it has a common field kis_device_common *common; if ((common = (kis_device_common *) tracked_vec[x]->fetch(devcomp_ref_common)) != NULL) { if (in_fd == -1) globalreg->kisnetserver->SendToAll(proto_ref_commondevice, (void *) &common); else globalreg->kisnetserver->SendToClient(in_fd, proto_ref_commondevice, (void *) &common, &cache); } } } int Devicetracker::TimerKick() { for (unsigned int x = 0; x < dirty_device_vec.size(); x++) { kis_tracked_device *dev = dirty_device_vec[x]; // If it has a common field kis_device_common *common; if ((common = (kis_device_common *) dev->fetch(devcomp_ref_common)) != NULL) { globalreg->kisnetserver->SendToAll(proto_ref_commondevice, (void *) &common); } } for (map::iterator x = phy_handler_map.begin(); x != phy_handler_map.end(); ++x) { x->second->TimerKick(); } return 1; } kismet-2013-03-R1b/dumpfile_netxml.cc0000664000175000017500000007346212124602454017172 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "globalregistry.h" #include "gpsdclient.h" #include "dumpfile_netxml.h" #include "packetsource.h" #include "packetsourcetracker.h" Dumpfile_Netxml::Dumpfile_Netxml() { fprintf(stderr, "FATAL OOPS: Dumpfile_Netxml called with no globalreg\n"); exit(1); } Dumpfile_Netxml::Dumpfile_Netxml(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; xmlfile = NULL; type = "netxml"; if (globalreg->netracker == NULL) { fprintf(stderr, "FATAL OOPS: Netracker missing before Dumpfile_Netxml\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Config file missing before Dumpfile_Netxml\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("netxml")) == "" || globalreg->fatal_condition) { return; } if ((xmlfile = fopen(fname.c_str(), "w")) == NULL) { _MSG("Failed to open netxml log file '" + fname + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } globalreg->RegisterDumpFile(this); _MSG("Opened netxml log file '" + fname + "'", MSGFLAG_INFO); } Dumpfile_Netxml::~Dumpfile_Netxml() { // Close files if (xmlfile != NULL) { Flush(); } xmlfile = NULL; if (export_filter != NULL) delete export_filter; } int Dumpfile_Netxml::Flush() { if (xmlfile != NULL) fclose(xmlfile); string tempname = fname + ".temp"; if ((xmlfile = fopen(tempname.c_str(), "w")) == NULL) { _MSG("Failed to open temporary netxml file for writing: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } // Write the XML headers fprintf(xmlfile, "\n" "\n\n"); fprintf(xmlfile, "\n\n", globalreg->version_major.c_str(), globalreg->version_minor.c_str(), globalreg->version_tiny.c_str(), ctime(&(globalreg->start_time))); // Get the source info const vector *sources = globalreg->sourcetracker->FetchSourceVec(); for (unsigned int s = 0; s < sources->size(); s++) { if ((*sources)[s]->strong_source == NULL) continue; fprintf(xmlfile, "\n", (*sources)[s]->strong_source->FetchUUID().UUID2String().c_str()); fprintf(xmlfile, " %s\n", SanitizeXML((*sources)[s]->sourceline).c_str()); fprintf(xmlfile, " %s\n", SanitizeXML((*sources)[s]->strong_source->FetchName()).c_str()); fprintf(xmlfile, " %s\n", SanitizeXML((*sources)[s]->strong_source->FetchInterface()).c_str()); fprintf(xmlfile, " %s\n", SanitizeXML((*sources)[s]->strong_source->FetchType()).c_str()); fprintf(xmlfile, " %d\n", (*sources)[s]->strong_source->FetchNumPackets()); fprintf(xmlfile, " %s\n", ((*sources)[s]->channel_dwell || (*sources)[s]->channel_hop) ? "true" : "false"); if ((*sources)[s]->channel_ptr != NULL) { string channels; for (unsigned int c = 0; c < (*sources)[s]->channel_ptr->channel_vec.size(); c++) { if ((*sources)[s]->channel_ptr->channel_vec[c].range == 0) { channels += IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.chan_t.channel); if ((*sources)[s]->channel_ptr->channel_vec[c].u.chan_t.dwell > 1) channels += string(":") + IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.chan_t.dwell); } else { channels += string("range-") + IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.range_t.start) + string("-") + IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.range_t.end) + string("-") + IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.range_t.width) + string("-") + IntToString((*sources)[s]->channel_ptr->channel_vec[c].u.range_t.iter); } if (c != (*sources)[s]->channel_ptr->channel_vec.size() - 1) channels += ","; } fprintf(xmlfile, " %s\n", channels.c_str()); } fprintf(xmlfile, "\n"); } // Get the tracked network and client->ap maps const map tracknet = globalreg->netracker->FetchTrackedNets(); map::const_iterator x; map::const_iterator y; int netnum = 0; // Dump all the networks for (x = tracknet.begin(); x != tracknet.end(); ++x) { netnum++; if (export_filter->RunFilter(x->second->bssid, mac_addr(0), mac_addr(0))) continue; Netracker::tracked_network *net = x->second; if (net->type == network_remove) continue; string ntype; switch (net->type) { case network_ap: ntype = "infrastructure"; break; case network_adhoc: ntype = "ad-hoc"; break; case network_probe: ntype = "probe"; break; case network_data: ntype = "data"; break; case network_turbocell: ntype = "turbocell"; break; default: ntype = "unknown"; break; } fprintf(xmlfile, " first_time))); fprintf(xmlfile, "last-time=\"%.24s\">\n", ctime(&(net->last_time))); for (map::iterator m = net->ssid_map.begin(); m != net->ssid_map.end(); ++m) { string adtype; if (m->second->type == ssid_beacon) adtype = "Beacon"; else if (m->second->type == ssid_proberesp) adtype = "Probe Response"; else if (m->second->type == ssid_file) adtype = "Cached SSID"; fprintf(xmlfile, " second->first_time))); fprintf(xmlfile, "last-time=\"%.24s\">\n" " %s\n" " %f\n" " %d\n", ctime(&(m->second->last_time)), adtype.c_str(), m->second->maxrate, m->second->packets); if (m->second->beaconrate != 0) fprintf(xmlfile, " %d\n", m->second->beaconrate); if (m->second->cryptset == 0) fprintf(xmlfile, " None\n"); if (m->second->cryptset == crypt_wep) fprintf(xmlfile, " WEP\n"); if (m->second->cryptset & crypt_layer3) fprintf(xmlfile, " Layer3\n"); if (m->second->cryptset & crypt_wpa_migmode) fprintf(xmlfile, " WPA Migration Mode\n"); if (m->second->cryptset & crypt_wep40) fprintf(xmlfile, " WEP40\n"); if (m->second->cryptset & crypt_wep104) fprintf(xmlfile, " WEP104\n"); /* if (m->second->cryptset & crypt_wpa) fprintf(xmlfile, " WPA\n"); */ if (m->second->cryptset & crypt_tkip) fprintf(xmlfile, " WPA+TKIP\n"); if (m->second->cryptset & crypt_psk) fprintf(xmlfile, " WPA+PSK\n"); if (m->second->cryptset & crypt_aes_ocb) fprintf(xmlfile, " WPA+AES-OCB\n"); if (m->second->cryptset & crypt_aes_ccm) fprintf(xmlfile, " WPA+AES-CCM\n"); if (m->second->cryptset & crypt_leap) fprintf(xmlfile, " WPA+LEAP\n"); if (m->second->cryptset & crypt_ttls) fprintf(xmlfile, " WPA+TTLS\n"); if (m->second->cryptset & crypt_tls) fprintf(xmlfile, " WPA+TLS\n"); if (m->second->cryptset & crypt_peap) fprintf(xmlfile, " WPA+PEAP\n"); if (m->second->cryptset & crypt_isakmp) fprintf(xmlfile, " ISAKMP\n"); if (m->second->cryptset & crypt_pptp) fprintf(xmlfile, " PPTP\n"); if (m->second->cryptset & crypt_fortress) fprintf(xmlfile, " Fortress\n"); if (m->second->cryptset & crypt_keyguard) fprintf(xmlfile, " Keyguard\n"); if (m->second->dot11d_vec.size() > 0) { fprintf(xmlfile, " \n", SanitizeXML(m->second->dot11d_country).c_str()); for (unsigned int z = 0; z < m->second->dot11d_vec.size(); z++) { fprintf(xmlfile, " \n", m->second->dot11d_vec[z].startchan, m->second->dot11d_vec[z].startchan + m->second->dot11d_vec[z].numchan - 1, m->second->dot11d_vec[z].txpower); } fprintf(xmlfile, " \n"); } fprintf(xmlfile, " %s\n", m->second->ssid_cloaked ? "true" : "false", SanitizeXML(m->second->ssid).c_str()); if (m->second->beacon_info.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(m->second->beacon_info).c_str()); fprintf(xmlfile, " \n"); } fprintf(xmlfile, " %s\n", net->bssid.Mac2String().c_str()); fprintf(xmlfile, " %s\n", SanitizeXML(net->manuf).c_str()); fprintf(xmlfile, " %d\n", net->channel); for (map::const_iterator fmi = net->freq_mhz_map.begin(); fmi != net->freq_mhz_map.end(); ++fmi) { fprintf(xmlfile, " %u %u\n", fmi->first, fmi->second); } fprintf(xmlfile, " %ld\n", (long) net->snrdata.maxseenrate * 100); if (net->snrdata.carrierset & (1 << (int) carrier_80211b)) fprintf(xmlfile, " IEEE 802.11b\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211bplus)) fprintf(xmlfile, " IEEE 802.11b+\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211a)) fprintf(xmlfile, " IEEE 802.11a\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211g)) fprintf(xmlfile, " IEEE 802.11g\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211fhss)) fprintf(xmlfile, " IEEE 802.11 FHSS\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211dsss)) fprintf(xmlfile, " IEEE 802.11 DSSS\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211n20)) fprintf(xmlfile, " IEEE 802.11n 20MHz\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211n40)) fprintf(xmlfile, " IEEE 802.11n 40MHz\n"); if (net->snrdata.encodingset & (1 << (int) encoding_cck)) fprintf(xmlfile, " CCK\n"); if (net->snrdata.encodingset & (1 << (int) encoding_pbcc)) fprintf(xmlfile, " PBCC\n"); if (net->snrdata.encodingset & (1 << (int) encoding_ofdm)) fprintf(xmlfile, " OFDM\n"); if (net->snrdata.encodingset & (1 << (int) encoding_dynamiccck)) fprintf(xmlfile, " Dynamic CCK-OFDM\n"); if (net->snrdata.encodingset & (1 << (int) encoding_gfsk)) fprintf(xmlfile, " GFSK\n"); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %d\n", net->llc_packets); fprintf(xmlfile, " %d\n", net->data_packets); fprintf(xmlfile, " %d\n", net->crypt_packets); // TODO - DupeIV stuff? fprintf(xmlfile, " %d\n", net->llc_packets + net->data_packets); fprintf(xmlfile, " %d\n", net->fragments); fprintf(xmlfile, " %d\n", net->retries); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %llu\n", (long long unsigned int) net->datasize); if (net->snrdata.last_signal_rssi != 0 || net->snrdata.last_signal_dbm != 0) { fprintf(xmlfile, " \n"); fprintf(xmlfile, " %d\n", net->snrdata.last_signal_dbm); fprintf(xmlfile, " %d\n", net->snrdata.last_noise_dbm); fprintf(xmlfile, " %d\n", net->snrdata.last_signal_rssi); fprintf(xmlfile, " %d\n", net->snrdata.last_noise_rssi); fprintf(xmlfile, " %d\n", net->snrdata.min_signal_dbm); fprintf(xmlfile, " %d\n", net->snrdata.min_noise_dbm); fprintf(xmlfile, " %d\n", net->snrdata.min_signal_rssi); fprintf(xmlfile, " %d\n", net->snrdata.min_noise_rssi); fprintf(xmlfile, " %d\n", net->snrdata.max_signal_dbm); fprintf(xmlfile, " %d\n", net->snrdata.max_noise_dbm); fprintf(xmlfile, " %d\n", net->snrdata.max_signal_rssi); fprintf(xmlfile, " %d\n", net->snrdata.max_noise_rssi); fprintf(xmlfile, " \n"); } if (net->gpsdata.gps_valid) { fprintf(xmlfile, " \n"); fprintf(xmlfile, " %f\n", net->gpsdata.min_lat); fprintf(xmlfile, " %f\n", net->gpsdata.min_lon); fprintf(xmlfile, " %f\n", net->gpsdata.min_alt); fprintf(xmlfile, " %f\n", net->gpsdata.min_spd); fprintf(xmlfile, " %f\n", net->gpsdata.max_lat); fprintf(xmlfile, " %f\n", net->gpsdata.max_lon); fprintf(xmlfile, " %f\n", net->gpsdata.max_alt); fprintf(xmlfile, " %f\n", net->gpsdata.max_spd); fprintf(xmlfile, " %f\n", net->snrdata.peak_lat); fprintf(xmlfile, " %f\n", net->snrdata.peak_lon); fprintf(xmlfile, " %f\n", net->snrdata.peak_alt); fprintf(xmlfile, " %f\n", net->gpsdata.aggregate_lat); fprintf(xmlfile, " %f\n", net->gpsdata.aggregate_lon); fprintf(xmlfile, " %f\n", net->gpsdata.aggregate_alt); fprintf(xmlfile, " \n"); } for (map::const_iterator ai = net->arb_tag_map.begin(); ai != net->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; fprintf(xmlfile, "%s\n", SanitizeXML(ai->first).c_str(), SanitizeXML(ai->second).c_str()); } if (net->guess_ipdata.ip_type > ipdata_factoryguess && net->guess_ipdata.ip_type < ipdata_group) { string iptype; switch (net->guess_ipdata.ip_type) { case ipdata_udptcp: iptype = "UDP/TCP"; break; case ipdata_arp: iptype = "ARP"; break; case ipdata_dhcp: iptype = "DHCP"; break; default: iptype = "Unknown"; break; } fprintf(xmlfile, " \n", iptype.c_str()); fprintf(xmlfile, " %s\n", inet_ntoa(net->guess_ipdata.ip_addr_block)); fprintf(xmlfile, " %s\n", inet_ntoa(net->guess_ipdata.ip_netmask)); fprintf(xmlfile, " %s\n", inet_ntoa(net->guess_ipdata.ip_gateway)); fprintf(xmlfile, " \n"); } fprintf(xmlfile, " %llu\n", (long long unsigned int) net->bss_timestamp); fprintf(xmlfile, " %s\n", SanitizeXML(net->cdp_dev_id).c_str()); fprintf(xmlfile, " %s\n", SanitizeXML(net->cdp_port_id).c_str()); for (map::iterator sdi = net->source_map.begin(); sdi != net->source_map.end(); ++sdi) { KisPacketSource *kps = globalreg->sourcetracker->FindKisPacketSourceUUID(sdi->second->source_uuid); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %s\n", kps->FetchUUID().UUID2String().c_str()); fprintf(xmlfile, " %.24s\n", ctime((const time_t *) &(sdi->second->last_seen))); fprintf(xmlfile, " %d\n", sdi->second->num_packets); fprintf(xmlfile, " \n"); } int clinum = 0; // Get the client range pairs and print them out for (y = net->client_map.begin(); y != net->client_map.end(); ++y) { Netracker::tracked_client *cli = y->second; clinum++; if (cli->type == client_remove) continue; string ctype; switch (cli->type) { case client_fromds: ctype = "fromds"; break; case client_tods: ctype = "tods"; break; case client_interds: ctype = "interds"; break; case client_established: ctype = "established"; break; case client_adhoc: ctype = "ad-hoc"; break; default: ctype = "unknown"; break; } fprintf(xmlfile, " last_time))); fprintf(xmlfile, "last-time=\"%.24s\">\n", ctime(&(cli->last_time))); fprintf(xmlfile, " %s\n", cli->mac.Mac2String().c_str()); fprintf(xmlfile, " %s\n", SanitizeXML(cli->manuf).c_str()); for (map::iterator m = cli->ssid_map.begin(); m != cli->ssid_map.end(); ++m) { string adtype; if (m->second->type == ssid_beacon) adtype = "Beacon"; else if (m->second->type == ssid_proberesp) adtype = "Probe Response"; else if (m->second->type == ssid_probereq) adtype = "Probe Request"; fprintf(xmlfile, " second->first_time))); fprintf(xmlfile, "last-time=\"%.24s\">\n" " %s\n" " %f\n" " %d\n", ctime(&(m->second->last_time)), adtype.c_str(), m->second->maxrate, m->second->packets); if (m->second->beaconrate != 0) fprintf(xmlfile, " %d\n", m->second->beaconrate); if (m->second->dot11d_vec.size() > 0) { fprintf(xmlfile, " \n", SanitizeXML(m->second->dot11d_country).c_str()); for (unsigned int z = 0; z < m->second->dot11d_vec.size(); z++) { fprintf(xmlfile, " \n", m->second->dot11d_vec[z].startchan, m->second->dot11d_vec[z].numchan, m->second->dot11d_vec[z].txpower); } fprintf(xmlfile, " \n"); } if (m->second->cryptset == 0) fprintf(xmlfile, " None\n"); if (m->second->cryptset & crypt_wep) fprintf(xmlfile, " WEP\n"); if (m->second->cryptset & crypt_layer3) fprintf(xmlfile, " Layer3\n"); if (m->second->cryptset & crypt_wep40) fprintf(xmlfile, " WEP40\n"); if (m->second->cryptset & crypt_wep104) fprintf(xmlfile, " WEP104\n"); if (m->second->cryptset & crypt_tkip) fprintf(xmlfile, " TKIP\n"); if (m->second->cryptset & crypt_wpa) fprintf(xmlfile, " WPA\n"); if (m->second->cryptset & crypt_psk) fprintf(xmlfile, " PSK\n"); if (m->second->cryptset & crypt_aes_ocb) fprintf(xmlfile, " AES-OCB\n"); if (m->second->cryptset & crypt_aes_ccm) fprintf(xmlfile, " AES-CCM\n"); if (m->second->cryptset & crypt_leap) fprintf(xmlfile, " LEAP\n"); if (m->second->cryptset & crypt_ttls) fprintf(xmlfile, " TTLS\n"); if (m->second->cryptset & crypt_tls) fprintf(xmlfile, " TLS\n"); if (m->second->cryptset & crypt_peap) fprintf(xmlfile, " PEAP\n"); if (m->second->cryptset & crypt_isakmp) fprintf(xmlfile, " ISAKMP\n"); if (m->second->cryptset & crypt_pptp) fprintf(xmlfile, " PPTP\n"); if (m->second->cryptset & crypt_fortress) fprintf(xmlfile, " Fortress\n"); if (m->second->cryptset & crypt_keyguard) fprintf(xmlfile, " Keyguard\n"); if (m->second->ssid_cloaked == 0) fprintf(xmlfile, " %s\n", SanitizeXML(m->second->ssid).c_str()); if (m->second->beacon_info.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(m->second->beacon_info).c_str()); fprintf(xmlfile, " \n"); } fprintf(xmlfile, " %d\n", cli->channel); for (map::const_iterator fmi = cli->freq_mhz_map.begin(); fmi != cli->freq_mhz_map.end(); ++fmi) { fprintf(xmlfile, " %u %u\n", fmi->first, fmi->second); } fprintf(xmlfile, " %ld\n", (long) cli->snrdata.maxseenrate * 100); if (cli->snrdata.carrierset & (1 << (int) carrier_80211b)) fprintf(xmlfile, " IEEE 802.11b" "\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211bplus)) fprintf(xmlfile, " IEEE 802.11b+" "\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211a)) fprintf(xmlfile, " IEEE 802.11a" "\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211g)) fprintf(xmlfile, " IEEE 802.11g" "\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211fhss)) fprintf(xmlfile, " IEEE 802.11 FHSS" "\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211dsss)) fprintf(xmlfile, " IEEE 802.11 DSSS" "\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_cck)) fprintf(xmlfile, " CCK\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_pbcc)) fprintf(xmlfile, " PBCC\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_ofdm)) fprintf(xmlfile, " OFDM\n"); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %d\n", cli->llc_packets); fprintf(xmlfile, " %d\n", cli->data_packets); fprintf(xmlfile, " %d\n", cli->crypt_packets); // TODO - DupeIV stuff? fprintf(xmlfile, " %d\n", cli->llc_packets + cli->data_packets); fprintf(xmlfile, " %d\n", cli->fragments); fprintf(xmlfile, " %d\n", cli->retries); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %llu\n", (long long unsigned int) cli->datasize); if (cli->snrdata.last_signal_rssi != 0 || cli->snrdata.last_signal_dbm != 0) { fprintf(xmlfile, " \n"); fprintf(xmlfile, " %d\n", cli->snrdata.last_signal_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.last_noise_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.last_signal_rssi); fprintf(xmlfile, " %d\n", cli->snrdata.last_noise_rssi); fprintf(xmlfile, " %d\n", cli->snrdata.min_signal_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.min_noise_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.min_signal_rssi); fprintf(xmlfile, " %d\n", cli->snrdata.min_noise_rssi); fprintf(xmlfile, " %d\n", cli->snrdata.max_signal_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.max_noise_dbm); fprintf(xmlfile, " %d\n", cli->snrdata.max_signal_rssi); fprintf(xmlfile, " %d\n", cli->snrdata.max_noise_rssi); fprintf(xmlfile, " \n"); } if (cli->gpsdata.gps_valid) { fprintf(xmlfile, " \n"); fprintf(xmlfile, " %f\n", cli->gpsdata.min_lat); fprintf(xmlfile, " %f\n", cli->gpsdata.min_lon); fprintf(xmlfile, " %f\n", cli->gpsdata.min_alt); fprintf(xmlfile, " %f\n", cli->gpsdata.min_spd); fprintf(xmlfile, " %f\n", cli->gpsdata.max_lat); fprintf(xmlfile, " %f\n", cli->gpsdata.max_lon); fprintf(xmlfile, " %f\n", cli->gpsdata.max_alt); fprintf(xmlfile, " %f\n", cli->gpsdata.max_spd); fprintf(xmlfile, " %f\n", cli->snrdata.peak_lat); fprintf(xmlfile, " %f\n", cli->snrdata.peak_lon); fprintf(xmlfile, " %f\n", cli->snrdata.peak_alt); fprintf(xmlfile, " %f\n", cli->gpsdata.aggregate_lat); fprintf(xmlfile, " %f\n", cli->gpsdata.aggregate_lon); fprintf(xmlfile, " %f\n", cli->gpsdata.aggregate_alt); fprintf(xmlfile, " \n"); } if (cli->guess_ipdata.ip_type > ipdata_factoryguess && cli->guess_ipdata.ip_type < ipdata_group) { string iptype; switch (cli->guess_ipdata.ip_type) { case ipdata_udptcp: iptype = "UDP/TCP"; break; case ipdata_arp: iptype = "ARP"; break; case ipdata_dhcp: iptype = "DHCP"; break; default: iptype = "Unknown"; break; } fprintf(xmlfile, " \n", iptype.c_str()); fprintf(xmlfile, " %s\n", inet_ntoa(cli->guess_ipdata.ip_addr_block)); fprintf(xmlfile, " %s\n", inet_ntoa(cli->guess_ipdata.ip_netmask)); fprintf(xmlfile, " %s\n", inet_ntoa(cli->guess_ipdata.ip_gateway)); fprintf(xmlfile, " \n"); } if (cli->cdp_dev_id.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(cli->cdp_dev_id).c_str()); if (cli->cdp_port_id.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(cli->cdp_port_id).c_str()); if (cli->dhcp_host.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(cli->dhcp_host).c_str()); if (cli->dhcp_vendor.length() > 0) fprintf(xmlfile, " %s\n", SanitizeXML(cli->dhcp_vendor).c_str()); for (map::iterator sdi = cli->source_map.begin(); sdi != cli->source_map.end(); ++sdi) { KisPacketSource *kps = globalreg->sourcetracker->FindKisPacketSourceUUID(sdi->second->source_uuid); fprintf(xmlfile, " \n"); fprintf(xmlfile, " %s\n", kps->FetchUUID().UUID2String().c_str()); fprintf(xmlfile, " %.24s\n", ctime((const time_t *) &(sdi->second->last_seen))); fprintf(xmlfile, " %d\n", sdi->second->num_packets); fprintf(xmlfile, " \n"); } for (map::const_iterator ai = cli->arb_tag_map.begin(); ai != cli->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; fprintf(xmlfile, " %s\n", SanitizeXML(ai->first).c_str(), SanitizeXML(ai->second).c_str()); } fprintf(xmlfile, " \n"); } fprintf(xmlfile, " \n"); } fprintf(xmlfile, "\n"); fflush(xmlfile); fclose(xmlfile); xmlfile = NULL; if (rename(tempname.c_str(), fname.c_str()) < 0) { _MSG("Failed to rename netxml temp file " + tempname + " to " + fname + ":" + string(strerror(errno)), MSGFLAG_ERROR); return -1; } dumped_frames = netnum; return 1; } kismet-2013-03-R1b/config.h.in0000664000175000017500000001615512124602454015506 0ustar dragorndragorn/* config.h.in. Generated from configure.in by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* system binary directory */ #undef BIN_LOC /* system data directory */ #undef DATA_LOC /* libairpcap header */ #undef HAVE_AIRPCAP_H /* BSD radiotap packet headers */ #undef HAVE_BSD_SYS_RADIOTAP /* kernel capability support */ #undef HAVE_CAPABILITY /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* system defines getopt_long */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* GPS support will be built. */ #undef HAVE_GPS /* inttypes.h is present */ #undef HAVE_INTTYPES_H /* libairpcap win32 control lib */ #undef HAVE_LIBAIRPCAP /* Define to 1 if you have the `cap' library (-lcap). */ #undef HAVE_LIBCAP /* Curses terminal lib */ #undef HAVE_LIBCURSES /* NCurses terminal lib */ #undef HAVE_LIBNCURSES /* libnl netlink library */ #undef HAVE_LIBNL /* libnl-2.0 netlink library */ #undef HAVE_LIBNL20 /* libnl-3.0 netlink library */ #undef HAVE_LIBNL30 /* Panel terminal lib */ #undef HAVE_LIBPANEL /* libpcap packet capture lib */ #undef HAVE_LIBPCAP /* libpcre regex support */ #undef HAVE_LIBPCRE /* Define to 1 if you have the header file. */ #undef HAVE_LIBUTIL_H /* Linux wireless iwfreq.flag */ #undef HAVE_LINUX_IWFREQFLAG /* Netlink works */ #undef HAVE_LINUX_NETLINK /* Linux wireless extentions present */ #undef HAVE_LINUX_WIRELESS /* local radiotap packet headers */ #undef HAVE_LOCAL_RADIOTAP /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* pcap/pcap.h */ #undef HAVE_PCAPPCAP_H /* pcapfileno-capable libwpcap */ #undef HAVE_PCAP_FILENO /* Selectablefd-capable libpcap */ #undef HAVE_PCAP_GETSELFD /* libpcap header */ #undef HAVE_PCAP_H /* Nonblocking-capable libpcap */ #undef HAVE_PCAP_NONBLOCK /* libpcap supports PPI */ #undef HAVE_PPI /* Define to 1 if you have the `pstat' function. */ #undef HAVE_PSTAT /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* accept() takes type socklen_t for addrlen */ #undef HAVE_SOCKLEN_T /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* stdint.h is present */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* System headers are there */ #undef HAVE_SYSHEADERS /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PSTAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_WIN32_EXTENSIONS_H /* Define to 1 if you have the header file. */ #undef HAVE_WINDOWS_H /* __PROGNAME glibc macro available */ #undef HAVE___PROGNAME /* system library directory */ #undef LIB_LOC /* system state directory */ #undef LOCALSTATE_DIR /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* writeable argv type */ #undef PF_ARGV_TYPE /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* system config directory */ #undef SYSCONF_LOC /* Compiling for Cygwin */ #undef SYS_CYGWIN /* Compiling for OSX/Darwin */ #undef SYS_DARWIN /* Compiling for FreeBSD */ #undef SYS_FREEBSD /* Compiling for Linux OS */ #undef SYS_LINUX /* Compiling for NetBSD */ #undef SYS_NETBSD /* Compiling for OpenBSD */ #undef SYS_OPENBSD /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* proftpd argv stuff */ #define PF_ARGV_NONE 0 #define PF_ARGV_NEW 1 #define PF_ARGV_WRITEABLE 2 #define PF_ARGV_PSTAT 3 #define PF_ARGV_PSSTRINGS 4 /* Maximum number of characters in the status line */ #define STATUS_MAX 1024 /* Maximum number of channels - I've only ever heard of 14 being used. */ #define CHANNEL_MAX 14 /* Stupid ncurses */ #define NCURSES_NOMACROS /* Number of hex pairs in a key */ #define WEPKEY_MAX 32 /* String length of a key */ #define WEPKEYSTR_MAX ((WEPKEY_MAX * 2) + WEPKEY_MAX) /* Number of past alerts to queue for new clients */ #define ALERT_BACKLOG 50 /* system min isn't reliable */ #define kismin(x,y) ((x) < (y) ? (x) : (y)) #define kismax(x,y) ((x) > (y) ? (x) : (y)) // Timer slices per second #define SERVER_TIMESLICES_SEC 10 // Max chars in SSID #define MAX_SSID_LEN 255 /* Namespace (on non-obj-c files) */ #ifndef __IN_OBJC_FILE__ using namespace std; #define __STL_USE_NAMESPACES #endif #ifndef _ #define _(x) x #endif kismet-2013-03-R1b/nl80211.h0000664000175000017500000011000512124602454014626 0ustar dragorndragorn#ifndef __LINUX_NL80211_H #define __LINUX_NL80211_H /* * 802.11 netlink interface public header * * Copyright 2006, 2007, 2008 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch * Copyright 2008 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /** * DOC: Station handling * * Stations are added per interface, but a special case exists with VLAN * interfaces. When a station is bound to an AP interface, it may be moved * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). * The station is still assumed to belong to the AP interface it was added * to. * * TODO: need more info? */ /** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors * * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request * to get a list of all present wiphys. * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request * or rename notification. Has attributes %NL80211_ATTR_WIPHY and * %NL80211_ATTR_WIPHY_NAME. * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. * * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; * either a dump request on a %NL80211_ATTR_WIPHY or a specific get * on an %NL80211_ATTR_IFINDEX is supported. * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also * be sent from userspace to request creation of a new virtual interface, * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and * %NL80211_ATTR_IFNAME. * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from * userspace to request deletion of a virtual interface, then requires * attribute %NL80211_ATTR_IFINDEX. * * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER * attributes. * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX * or %NL80211_ATTR_MAC. * * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a * %NL80222_CMD_NEW_BEACON message) * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, * parameters are like for %NL80211_CMD_SET_BEACON. * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it * * @NL80211_CMD_GET_STATION: Get station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_SET_STATION: Set station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified * by %NL80211_ATTR_IFINDEX. * * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by * %NL80211_ATTR_IFINDEX. * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to * destination %NL80211_ATTR_MAC on the interface identified by * %NL80211_ATTR_IFINDEX. * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the * the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC * or, if no MAC address given, all mesh paths, on the interface identified * by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by * %NL80211_ATTR_IFINDEX. * * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set * regulatory domain. * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command * after being queried by the kernel. CRDA replies by sending a regulatory * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our * current alpha2 if it found a match. It also provides * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each * regulatory rule is a nested set of attributes given by * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will * store this as a valid request and then query userspace for it. * * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the * interface identified by %NL80211_ATTR_IFINDEX * * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The * interface is identified with %NL80211_ATTR_IFINDEX and the management * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be * added to the end of the specified management frame is specified with * %NL80211_ATTR_IE. If the command succeeds, the requested data will be * added to all specified management frames generated by * kernel/firmware/driver. * * @NL80211_CMD_GET_SCAN: get scan results * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to * NL80211_CMD_GET_SCAN and on the "scan" multicast group) * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain * has been changed and provides details of the request information * that caused the change such as who initiated the regulatory request * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on * to (%NL80211_ATTR_REG_ALPHA2). * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ enum nl80211_commands { /* don't change the order or add anything inbetween, this is ABI! */ NL80211_CMD_UNSPEC, NL80211_CMD_GET_WIPHY, /* can dump */ NL80211_CMD_SET_WIPHY, NL80211_CMD_NEW_WIPHY, NL80211_CMD_DEL_WIPHY, NL80211_CMD_GET_INTERFACE, /* can dump */ NL80211_CMD_SET_INTERFACE, NL80211_CMD_NEW_INTERFACE, NL80211_CMD_DEL_INTERFACE, NL80211_CMD_GET_KEY, NL80211_CMD_SET_KEY, NL80211_CMD_NEW_KEY, NL80211_CMD_DEL_KEY, NL80211_CMD_GET_BEACON, NL80211_CMD_SET_BEACON, NL80211_CMD_NEW_BEACON, NL80211_CMD_DEL_BEACON, NL80211_CMD_GET_STATION, NL80211_CMD_SET_STATION, NL80211_CMD_NEW_STATION, NL80211_CMD_DEL_STATION, NL80211_CMD_GET_MPATH, NL80211_CMD_SET_MPATH, NL80211_CMD_NEW_MPATH, NL80211_CMD_DEL_MPATH, NL80211_CMD_SET_BSS, NL80211_CMD_SET_REG, NL80211_CMD_REQ_SET_REG, NL80211_CMD_GET_MESH_PARAMS, NL80211_CMD_SET_MESH_PARAMS, NL80211_CMD_SET_MGMT_EXTRA_IE, NL80211_CMD_GET_REG, NL80211_CMD_GET_SCAN, NL80211_CMD_TRIGGER_SCAN, NL80211_CMD_NEW_SCAN_RESULTS, NL80211_CMD_SCAN_ABORTED, NL80211_CMD_REG_CHANGE, /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ __NL80211_CMD_AFTER_LAST, NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 }; /* * Allow user space programs to use #ifdef on new commands by defining them * here */ #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE #define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE /** * enum nl80211_attrs - nl80211 netlink attributes * * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors * * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. * /sys/class/ieee80211//index * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including * this attribute) * NL80211_CHAN_HT20 = HT20 only * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * * @NL80211_ATTR_MAC: MAC address (various uses) * * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC * keys * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 * section 7.3.2.25.1, e.g. 0x000FAC04) * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and * CCMP keys, each six bytes in little endian * * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE * * @NL80211_ATTR_STA_AID: Association ID for the station (u16) * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of * &enum nl80211_sta_flags. * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by * IEEE 802.11 7.3.1.6 (u16). * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported * rates as defined by IEEE 802.11 7.3.2.2 but without the length * restriction (at most %NL80211_MAX_SUPP_RATES). * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station * to, or the AP interface the station was originally added to to. * @NL80211_ATTR_STA_INFO: information about a station, part of station info * given for %NL80211_CMD_GET_STATION, nested attribute containing * info as possible, see &enum nl80211_sta_info. * * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, * consisting of a nested array. * * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path * info given for %NL80211_CMD_GET_MPATH, nested attribute described at * &enum nl80211_mpath_info. * * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of * &enum nl80211_mntr_flags. * * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the * current regulatory domain should be set to or is already set to. * For example, 'CR', for Costa Rica. This attribute is used by the kernel * to query the CRDA to retrieve one regulatory domain. This attribute can * also be used by userspace to query the kernel for the currently set * regulatory domain. We chose an alpha2 as that is also used by the * IEEE-802.11d country information element to identify a country. * Users can also simply ask the wireless core to set regulatory domain * to a specific alpha2. * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory * rules. * * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled * (u8, 0 or 1) * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled * (u8, 0 or 1) * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic * rates in format defined by IEEE 802.11 7.3.2.2 but without the length * restriction (at most %NL80211_MAX_SUPP_RATES). * * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) * * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all * supported interface types, each a flag attribute with the number * of the interface mode. * * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for * %NL80211_CMD_SET_MGMT_EXTRA_IE. * * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with * %NL80211_CMD_SET_MGMT_EXTRA_IE). * * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with * a single scan request, a wiphy attribute. * * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive * scanning and include a zero-length SSID (wildcard) for wildcard scan * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the * scan result list changes (BSS expired or added) so that applications * can verify that they got a single, consistent snapshot (when all dump * messages carried the same generation number) * @NL80211_ATTR_BSS: scan result BSS * * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ enum nl80211_attrs { /* don't change the order or add anything inbetween, this is ABI! */ NL80211_ATTR_UNSPEC, NL80211_ATTR_WIPHY, NL80211_ATTR_WIPHY_NAME, NL80211_ATTR_IFINDEX, NL80211_ATTR_IFNAME, NL80211_ATTR_IFTYPE, NL80211_ATTR_MAC, NL80211_ATTR_KEY_DATA, NL80211_ATTR_KEY_IDX, NL80211_ATTR_KEY_CIPHER, NL80211_ATTR_KEY_SEQ, NL80211_ATTR_KEY_DEFAULT, NL80211_ATTR_BEACON_INTERVAL, NL80211_ATTR_DTIM_PERIOD, NL80211_ATTR_BEACON_HEAD, NL80211_ATTR_BEACON_TAIL, NL80211_ATTR_STA_AID, NL80211_ATTR_STA_FLAGS, NL80211_ATTR_STA_LISTEN_INTERVAL, NL80211_ATTR_STA_SUPPORTED_RATES, NL80211_ATTR_STA_VLAN, NL80211_ATTR_STA_INFO, NL80211_ATTR_WIPHY_BANDS, NL80211_ATTR_MNTR_FLAGS, NL80211_ATTR_MESH_ID, NL80211_ATTR_STA_PLINK_ACTION, NL80211_ATTR_MPATH_NEXT_HOP, NL80211_ATTR_MPATH_INFO, NL80211_ATTR_BSS_CTS_PROT, NL80211_ATTR_BSS_SHORT_PREAMBLE, NL80211_ATTR_BSS_SHORT_SLOT_TIME, NL80211_ATTR_HT_CAPABILITY, NL80211_ATTR_SUPPORTED_IFTYPES, NL80211_ATTR_REG_ALPHA2, NL80211_ATTR_REG_RULES, NL80211_ATTR_MESH_PARAMS, NL80211_ATTR_BSS_BASIC_RATES, NL80211_ATTR_WIPHY_TXQ_PARAMS, NL80211_ATTR_WIPHY_FREQ, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_ATTR_KEY_DEFAULT_MGMT, NL80211_ATTR_MGMT_SUBTYPE, NL80211_ATTR_IE, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, NL80211_ATTR_SCAN_FREQUENCIES, NL80211_ATTR_SCAN_SSIDS, NL80211_ATTR_SCAN_GENERATION, NL80211_ATTR_BSS, NL80211_ATTR_REG_INITIATOR, NL80211_ATTR_REG_TYPE, /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; /* * Allow user space programs to use #ifdef on new attributes by defining them * here */ #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS #define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ #define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE #define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE #define NL80211_ATTR_IE NL80211_ATTR_IE #define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR #define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 /** * enum nl80211_iftype - (virtual) interface types * * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides * @NL80211_IFTYPE_ADHOC: independent BSS member * @NL80211_IFTYPE_STATION: managed BSS member * @NL80211_IFTYPE_AP: access point * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames * @NL80211_IFTYPE_MESH_POINT: mesh point * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @__NL80211_IFTYPE_AFTER_LAST: internal use * * These values are used with the %NL80211_ATTR_IFTYPE * to set the type of an interface. * */ enum nl80211_iftype { NL80211_IFTYPE_UNSPECIFIED, NL80211_IFTYPE_ADHOC, NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP, NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_WDS, NL80211_IFTYPE_MONITOR, NL80211_IFTYPE_MESH_POINT, /* keep last */ __NL80211_IFTYPE_AFTER_LAST, NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 }; /** * enum nl80211_sta_flags - station flags * * Station flags. When a station is added to an AP interface, it is * assumed to be already associated (and hence authenticated.) * * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames * with short barker preamble * @NL80211_STA_FLAG_WME: station is WME/QoS capable * @NL80211_STA_FLAG_MFP: station uses management frame protection */ enum nl80211_sta_flags { __NL80211_STA_FLAG_INVALID, NL80211_STA_FLAG_AUTHORIZED, NL80211_STA_FLAG_SHORT_PREAMBLE, NL80211_STA_FLAG_WME, NL80211_STA_FLAG_MFP, /* keep last */ __NL80211_STA_FLAG_AFTER_LAST, NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; /** * enum nl80211_rate_info - bitrate information * * These attribute types are used with %NL80211_STA_INFO_TXRATE * when getting information about the bitrate of a station. * * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { __NL80211_RATE_INFO_INVALID, NL80211_RATE_INFO_BITRATE, NL80211_RATE_INFO_MCS, NL80211_RATE_INFO_40_MHZ_WIDTH, NL80211_RATE_INFO_SHORT_GI, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 }; /** * enum nl80211_sta_info - station information * * These attribute types are used with %NL80211_ATTR_STA_INFO * when getting information about a station. * * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute * containing info as possible, see &enum nl80211_sta_info_txrate. * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this * station) */ enum nl80211_sta_info { __NL80211_STA_INFO_INVALID, NL80211_STA_INFO_INACTIVE_TIME, NL80211_STA_INFO_RX_BYTES, NL80211_STA_INFO_TX_BYTES, NL80211_STA_INFO_LLID, NL80211_STA_INFO_PLID, NL80211_STA_INFO_PLINK_STATE, NL80211_STA_INFO_SIGNAL, NL80211_STA_INFO_TX_BITRATE, NL80211_STA_INFO_RX_PACKETS, NL80211_STA_INFO_TX_PACKETS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 }; /** * enum nl80211_mpath_flags - nl80211 mesh path flags * * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded */ enum nl80211_mpath_flags { NL80211_MPATH_FLAG_ACTIVE = 1<<0, NL80211_MPATH_FLAG_RESOLVING = 1<<1, NL80211_MPATH_FLAG_DSN_VALID = 1<<2, NL80211_MPATH_FLAG_FIXED = 1<<3, NL80211_MPATH_FLAG_RESOLVED = 1<<4, }; /** * enum nl80211_mpath_info - mesh path information * * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting * information about a mesh path. * * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination * @NL80211_ATTR_MPATH_DSN: destination sequence number * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in * &enum nl80211_mpath_flags; * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries */ enum nl80211_mpath_info { __NL80211_MPATH_INFO_INVALID, NL80211_MPATH_INFO_FRAME_QLEN, NL80211_MPATH_INFO_DSN, NL80211_MPATH_INFO_METRIC, NL80211_MPATH_INFO_EXPTIME, NL80211_MPATH_INFO_FLAGS, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, NL80211_MPATH_INFO_DISCOVERY_RETRIES, /* keep last */ __NL80211_MPATH_INFO_AFTER_LAST, NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 }; /** * enum nl80211_band_attr - band attributes * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, * an array of nested frequency attributes * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, * an array of nested bitrate attributes * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as * defined in 802.11n * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n */ enum nl80211_band_attr { __NL80211_BAND_ATTR_INVALID, NL80211_BAND_ATTR_FREQS, NL80211_BAND_ATTR_RATES, NL80211_BAND_ATTR_HT_MCS_SET, NL80211_BAND_ATTR_HT_CAPA, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 }; #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA /** * enum nl80211_frequency_attr - frequency attributes * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is * permitted on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm * (100 * dBm). */ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER /** * enum nl80211_bitrate_attr - bitrate attributes * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported * in 2.4 GHz band. */ enum nl80211_bitrate_attr { __NL80211_BITRATE_ATTR_INVALID, NL80211_BITRATE_ATTR_RATE, NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, /* keep last */ __NL80211_BITRATE_ATTR_AFTER_LAST, NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 }; /** * enum nl80211_initiator - Indicates the initiator of a reg domain request * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world * regulatory domain. * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the * regulatory domain. * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the * wireless core it thinks its knows the regulatory domain we should be in. * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an * 802.11 country information element with regulatory information it * thinks we should consider. */ enum nl80211_reg_initiator { NL80211_REGDOM_SET_BY_CORE, NL80211_REGDOM_SET_BY_USER, NL80211_REGDOM_SET_BY_DRIVER, NL80211_REGDOM_SET_BY_COUNTRY_IE, }; /** * enum nl80211_reg_type - specifies the type of regulatory domain * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains * to a specific country. When this is set you can count on the * ISO / IEC 3166 alpha2 country code being valid. * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory * domain. * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom * driver specific world regulatory domain. These do not apply system-wide * and are only applicable to the individual devices which have requested * them to be applied. * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product * of an intersection between two regulatory domains -- the previously * set regulatory domain on the system and the last accepted regulatory * domain request to be processed. */ enum nl80211_reg_type { NL80211_REGDOM_TYPE_COUNTRY, NL80211_REGDOM_TYPE_WORLD, NL80211_REGDOM_TYPE_CUSTOM_WORLD, NL80211_REGDOM_TYPE_INTERSECTION, }; /** * enum nl80211_reg_rule_attr - regulatory rule attributes * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional * considerations for a given frequency range. These are the * &enum nl80211_reg_rule_flags. * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory * rule in KHz. This is not a center of frequency but an actual regulatory * band edge. * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule * in KHz. This is not a center a frequency but an actual regulatory * band edge. * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this * frequency range, in KHz. * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain * for a given frequency range. The value is in mBi (100 * dBi). * If you don't have one then don't send this. * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for * a given frequency range. The value is in mBm (100 * dBm). */ enum nl80211_reg_rule_attr { __NL80211_REG_RULE_ATTR_INVALID, NL80211_ATTR_REG_RULE_FLAGS, NL80211_ATTR_FREQ_RANGE_START, NL80211_ATTR_FREQ_RANGE_END, NL80211_ATTR_FREQ_RANGE_MAX_BW, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, NL80211_ATTR_POWER_RULE_MAX_EIRP, /* keep last */ __NL80211_REG_RULE_ATTR_AFTER_LAST, NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 }; /** * enum nl80211_reg_rule_flags - regulatory rule flags * * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed * @NL80211_RRF_NO_CCK: CCK modulation not allowed * @NL80211_RRF_NO_INDOOR: indoor operation not allowed * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links * @NL80211_RRF_PASSIVE_SCAN: passive scan is required * @NL80211_RRF_NO_IBSS: no IBSS is allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, NL80211_RRF_NO_CCK = 1<<1, NL80211_RRF_NO_INDOOR = 1<<2, NL80211_RRF_NO_OUTDOOR = 1<<3, NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, NL80211_RRF_PASSIVE_SCAN = 1<<7, NL80211_RRF_NO_IBSS = 1<<8, }; /** * enum nl80211_mntr_flags - monitor configuration flags * * Monitor configuration flags. * * @__NL80211_MNTR_FLAG_INVALID: reserved * * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP * @NL80211_MNTR_FLAG_CONTROL: pass control frames * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. * overrides all other flags. * * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag */ enum nl80211_mntr_flags { __NL80211_MNTR_FLAG_INVALID, NL80211_MNTR_FLAG_FCSFAIL, NL80211_MNTR_FLAG_PLCPFAIL, NL80211_MNTR_FLAG_CONTROL, NL80211_MNTR_FLAG_OTHER_BSS, NL80211_MNTR_FLAG_COOK_FRAMES, /* keep last */ __NL80211_MNTR_FLAG_AFTER_LAST, NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 }; /** * enum nl80211_meshconf_params - mesh configuration parameters * * Mesh configuration parameters * * @__NL80211_MESHCONF_INVALID: internal use * * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in * millisecond units, used by the Peer Link Open message * * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in * millisecond units, used by the peer link management to close a peer link * * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in * millisecond units * * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed * on this mesh interface * * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link * open retries that can be sent to establish a new peer link instance in a * mesh * * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh * point. * * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically * open peer links when we detect compatible mesh peers. * * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames * containing a PREQ that an MP can send to a particular destination (path * target) * * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths * (in milliseconds) * * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait * until giving up on a path discovery (in milliseconds) * * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh * points receiving a PREQ shall consider the forwarding information from the * root to be valid. (TU = time unit) * * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in * TUs) during which an MP can send only one action frame containing a PREQ * reference element * * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) * that it takes for an HWMP information element to propagate across the mesh * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { __NL80211_MESHCONF_INVALID, NL80211_MESHCONF_RETRY_TIMEOUT, NL80211_MESHCONF_CONFIRM_TIMEOUT, NL80211_MESHCONF_HOLDING_TIMEOUT, NL80211_MESHCONF_MAX_PEER_LINKS, NL80211_MESHCONF_MAX_RETRIES, NL80211_MESHCONF_TTL, NL80211_MESHCONF_AUTO_OPEN_PLINKS, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, NL80211_MESHCONF_PATH_REFRESH_TIME, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 }; /** * enum nl80211_txq_attr - TX queue parameter attributes * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning * disabled * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form * 2^n-1 in the range 1..32767] * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form * 2^n-1 in the range 1..32767] * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number */ enum nl80211_txq_attr { __NL80211_TXQ_ATTR_INVALID, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_ATTR_TXOP, NL80211_TXQ_ATTR_CWMIN, NL80211_TXQ_ATTR_CWMAX, NL80211_TXQ_ATTR_AIFS, /* keep last */ __NL80211_TXQ_ATTR_AFTER_LAST, NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 }; enum nl80211_txq_q { NL80211_TXQ_Q_VO, NL80211_TXQ_Q_VI, NL80211_TXQ_Q_BE, NL80211_TXQ_Q_BK }; enum nl80211_channel_type { NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, NL80211_CHAN_HT40MINUS, NL80211_CHAN_HT40PLUS }; /** * enum nl80211_bss - netlink attributes for a BSS * * @__NL80211_BSS_INVALID: invalid * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the * raw information elements from the probe response/beacon (bin) * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ enum nl80211_bss { __NL80211_BSS_INVALID, NL80211_BSS_BSSID, NL80211_BSS_FREQUENCY, NL80211_BSS_TSF, NL80211_BSS_BEACON_INTERVAL, NL80211_BSS_CAPABILITY, NL80211_BSS_INFORMATION_ELEMENTS, NL80211_BSS_SIGNAL_MBM, NL80211_BSS_SIGNAL_UNSPEC, /* keep last */ __NL80211_BSS_AFTER_LAST, NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 }; #endif /* __LINUX_NL80211_H */ kismet-2013-03-R1b/plugin-btscan/0000775000175000017500000000000012124602454016221 5ustar dragorndragornkismet-2013-03-R1b/plugin-btscan/tracker_btscan.h0000664000175000017500000000316712124602454021366 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TRACKER_DOT15D4_H__ #define __TRACKER_DOT15D4_H__ #include #include #include #include "packet_btscan.h" // Fwd def of logger class Dumpfile_Btscantxt; class btscan_network { public: btscan_network() { first_time = last_time = 0; packets = 0; } mac_addr bd_addr; string bd_name, bd_class; time_t first_time, last_time; unsigned int packets; kis_gps_data gpsdata; unsigned int dirty; }; class Tracker_BTScan { public: Tracker_BTScan() { fprintf(stderr, "FATAL OOPS: tracker_dot15d4()\n"); exit(1); } Tracker_BTScan(GlobalRegistry *in_globalreg); int chain_handler(kis_packet *in_pack); void BlitDevices(int in_fd); protected: GlobalRegistry *globalreg; map tracked_devs; int BTSCANDEV_ref; int timer_ref; // Friends with the logger for direct access friend class Dumpfile_Btscantxt; }; #endif kismet-2013-03-R1b/plugin-btscan/Makefile0000664000175000017500000000251512124602454017664 0ustar dragorndragorn# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ -lbluetooth -lpthread CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC SRVOBJS = packetsource_linuxbt.o tracker_btscan.o dumpfile_btscantxt.o kismet_btscan.o SRVOUT = btscan.so CLIOBJS = btscan_ui.o CLIOUT = btscan_ui.so all: $(SRVOUT) $(CLIOUT) $(CLIOUT): $(CLIOBJS) $(LD) $(PLUGINLDFLAGS) $(CLIOBJS) -o $(CLIOUT) $(LIBS) $(SRVOUT): $(SRVOBJS) $(LD) $(PLUGINLDFLAGS) $(SRVOBJS) -o $(SRVOUT) $(LIBS) install: $(SRVOUT) $(CLIOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $(SRVOUT) $(DESTDIR)/$(plugindir)/$(SRVOUT) mkdir -p $(DESTDIR)/$(plugindir)_client $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $(CLIOUT) $(DESTDIR)/$(plugindir)_client/$(CLIOUT) userinstall: $(SRVOUT) $(CLIOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) -v $(SRVOUT) ${HOME}/.kismet/plugins/$(SRVOUT) mkdir -p ${HOME}/.kismet/client_plugins/ $(INSTALL) -v $(CLIOUT) ${HOME}/.kismet/client_plugins/$(CLIOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/plugin-btscan/packet_btscan.h0000664000175000017500000000214612124602454021176 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKET_BTSCAN_H__ #define __PACKET_BTSCAN_H__ #include #include #include #include #include // TODO - expand to include SDP scan data class btscan_packinfo : public packet_component { public: btscan_packinfo() { self_destruct = 1; }; string bd_name; string bd_class; mac_addr bd_addr; }; #endif kismet-2013-03-R1b/plugin-btscan/btscan_ui.cc0000664000175000017500000005402212124602454020502 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include "tracker_btscan.h" const char *btscandev_fields[] = { "bdaddr", "name", "class", "firsttime", "lasttime", "packets", GPS_COMMON_FIELDS_TEXT, NULL }; enum btscan_sort_type { btscan_sort_bdaddr, btscan_sort_bdname, btscan_sort_bdclass, btscan_sort_firsttime, btscan_sort_lasttime, btscan_sort_packets }; struct btscan_data { int mi_plugin_btscan, mi_showbtscan; int mn_sub_sort, mi_sort_bdaddr, mi_sort_bdname, mi_sort_bdclass, mi_sort_firsttime, mi_sort_lasttime, mi_sort_packets; map btdev_map; vector btdev_vec; Kis_Scrollable_Table *btdevlist; int cliaddref; int timerid; string asm_btscandev_fields; int asm_btscandev_num; btscan_sort_type sort_type; KisPanelPluginData *pdata; Kis_Menu *menu; }; class Btscan_Sort_Bdaddr { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->bd_addr < y->bd_addr; } }; class Btscan_Sort_Firsttime { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->first_time < y->first_time; } }; class Btscan_Sort_Lasttime { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->last_time < y->last_time; } }; class Btscan_Sort_Class { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->bd_class < y->bd_class; } }; class Btscan_Sort_Name { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->bd_name < y->bd_name; } }; class Btscan_Sort_Packets { public: inline bool operator()(btscan_network *x, btscan_network *y) const { return x->packets < y->packets; } }; // Menu events int Btscan_plugin_menu_cb(void *auxptr); void Btscan_show_menu_cb(MENUITEM_CB_PARMS); void Btscan_sort_menu_cb(MENUITEM_CB_PARMS); // Network events void BtscanCliAdd(KPI_ADDCLI_CB_PARMS); void BtscanCliConfigured(CLICONF_CB_PARMS); // List select int BtscanDevlistCB(COMPONENT_CALLBACK_PARMS); // List content timer int BtscanTimer(TIMEEVENT_PARMS); // Details panel class Btscan_Details_Panel : public Kis_Panel { public: Btscan_Details_Panel() { fprintf(stderr, "FATAL OOPS: Btscan_Details_Panel()\n"); exit(1); } Btscan_Details_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Btscan_Details_Panel(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); void SetBtscan(btscan_data *in_bt) { btscan = in_bt; } void SetDetailsNet(btscan_network *in_net) { btnet = in_net; } protected: btscan_data *btscan; btscan_network *btnet; Kis_Panel_Packbox *vbox; Kis_Free_Text *btdetailt; Kis_Button *closebutton; }; extern "C" { int panel_plugin_init(GlobalRegistry *globalreg, KisPanelPluginData *pdata) { _MSG("Loading Kismet BTSCAN plugin", MSGFLAG_INFO); btscan_data *btscan = new btscan_data; pdata->pluginaux = (void *) btscan; btscan->pdata = pdata; btscan->sort_type = btscan_sort_bdaddr; btscan->asm_btscandev_num = TokenNullJoin(&(btscan->asm_btscandev_fields), btscandev_fields); btscan->mi_plugin_btscan = pdata->mainpanel->AddPluginMenuItem("BT Scan", Btscan_plugin_menu_cb, pdata); btscan->btdevlist = new Kis_Scrollable_Table(globalreg, pdata->mainpanel); vector titles; Kis_Scrollable_Table::title_data t; t.width = 17; t.title = "BD Addr"; t.alignment = 0; titles.push_back(t); t.width = 16; t.title = "Name"; t.alignment = 0; titles.push_back(t); t.width = 8; t.title = "Class"; t.alignment = 0; titles.push_back(t); t.width = 5; t.title = "Count"; t.alignment = 2; titles.push_back(t); btscan->btdevlist->AddTitles(titles); btscan->btdevlist->SetPreferredSize(0, 10); btscan->btdevlist->SetHighlightSelected(1); btscan->btdevlist->SetLockScrollTop(1); btscan->btdevlist->SetDrawTitles(1); btscan->btdevlist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, BtscanDevlistCB, btscan); pdata->mainpanel->AddComponentVec(btscan->btdevlist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); pdata->mainpanel->FetchNetBox()->Pack_After_Named("KIS_MAIN_NETLIST", btscan->btdevlist, 1, 0); btscan->menu = pdata->kpinterface->FetchMainPanel()->FetchMenu(); int mn_view = btscan->menu->FindMenu("View"); pdata->kpinterface->FetchMainPanel()->AddViewSeparator(); btscan->mi_showbtscan = btscan->menu->AddMenuItem("BT Scan", mn_view, 0); btscan->menu->SetMenuItemCallback(btscan->mi_showbtscan, Btscan_show_menu_cb, btscan); pdata->kpinterface->FetchMainPanel()->AddSortSeparator(); int mn_sort = btscan->menu->FindMenu("Sort"); btscan->mn_sub_sort = btscan->menu->AddSubMenuItem("BTScan", mn_sort, 0); btscan->mi_sort_bdaddr = btscan->menu->AddMenuItem("BD Addr", btscan->mn_sub_sort, 0); btscan->mi_sort_bdname = btscan->menu->AddMenuItem("Name", btscan->mn_sub_sort, 0); btscan->mi_sort_bdclass = btscan->menu->AddMenuItem("Class", btscan->mn_sub_sort, 0); btscan->mi_sort_firsttime = btscan->menu->AddMenuItem("First Time", btscan->mn_sub_sort, 0); btscan->mi_sort_lasttime = btscan->menu->AddMenuItem("Last Time", btscan->mn_sub_sort, 0); btscan->mi_sort_packets = btscan->menu->AddMenuItem("Times Seen", btscan->mn_sub_sort, 0); btscan->menu->SetMenuItemCallback(btscan->mi_sort_bdaddr, Btscan_sort_menu_cb, btscan); btscan->menu->SetMenuItemCallback(btscan->mi_sort_bdname, Btscan_sort_menu_cb, btscan); btscan->menu->SetMenuItemCallback(btscan->mi_sort_bdclass, Btscan_sort_menu_cb, btscan); btscan->menu->SetMenuItemCallback(btscan->mi_sort_firsttime, Btscan_sort_menu_cb, btscan); btscan->menu->SetMenuItemCallback(btscan->mi_sort_lasttime, Btscan_sort_menu_cb, btscan); btscan->menu->SetMenuItemCallback(btscan->mi_sort_packets, Btscan_sort_menu_cb, btscan); string opt = StrLower(pdata->kpinterface->prefs->FetchOpt("PLUGIN_BTSCAN_SHOW")); if (opt == "true" || opt == "") { btscan->btdevlist->Show(); btscan->menu->SetMenuItemChecked(btscan->mi_showbtscan, 1); btscan->menu->EnableMenuItem(btscan->mi_sort_bdaddr); btscan->menu->EnableMenuItem(btscan->mi_sort_bdname); btscan->menu->EnableMenuItem(btscan->mi_sort_bdclass); btscan->menu->EnableMenuItem(btscan->mi_sort_firsttime); btscan->menu->EnableMenuItem(btscan->mi_sort_lasttime); btscan->menu->EnableMenuItem(btscan->mi_sort_packets); } else { btscan->btdevlist->Hide(); btscan->menu->SetMenuItemChecked(btscan->mi_showbtscan, 0); btscan->menu->DisableMenuItem(btscan->mi_sort_bdaddr); btscan->menu->DisableMenuItem(btscan->mi_sort_bdname); btscan->menu->DisableMenuItem(btscan->mi_sort_bdclass); btscan->menu->DisableMenuItem(btscan->mi_sort_firsttime); btscan->menu->DisableMenuItem(btscan->mi_sort_lasttime); btscan->menu->DisableMenuItem(btscan->mi_sort_packets); } opt = pdata->kpinterface->prefs->FetchOpt("PLUGIN_BTSCAN_SORT"); if (opt == "bdaddr") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdaddr, 1); btscan->sort_type = btscan_sort_bdaddr; } else if (opt == "bdname") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdname, 1); btscan->sort_type = btscan_sort_bdname; } else if (opt == "bdclass") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdclass, 1); btscan->sort_type = btscan_sort_bdclass; } else if (opt == "firsttime") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_firsttime, 1); btscan->sort_type = btscan_sort_firsttime; } else if (opt == "lasttime") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_lasttime, 1); btscan->sort_type = btscan_sort_lasttime; } else if (opt == "packets") { btscan->menu->SetMenuItemChecked(btscan->mi_sort_packets, 1); btscan->sort_type = btscan_sort_packets; } else { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdaddr, 1); btscan->sort_type = btscan_sort_bdaddr; } // Register the timer event for populating the array btscan->timerid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &BtscanTimer, btscan); // Do this LAST. The configure event is responsible for clearing out the // list on reconnect, but MAY be called immediately upon being registered // if the client is already valid. We have to have made all the other // bits first before it's valid to call this btscan->cliaddref = pdata->kpinterface->Add_NetCli_AddCli_CB(BtscanCliAdd, (void *) btscan); return 1; } // Plugin version control void kis_revision_info(panel_plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } int Btscan_plugin_menu_cb(void *auxptr) { KisPanelPluginData *pdata = (KisPanelPluginData *) auxptr; pdata->kpinterface->RaiseAlert("BT Scan", "BT Scan UI " + string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY) + "\n" "\n" "Display Bluetooth/802.15.1 devices found by the\n" "BTSCAN active scanning Kismet plugin\n"); return 1; } void Btscan_show_menu_cb(MENUITEM_CB_PARMS) { btscan_data *btscan = (btscan_data *) auxptr; if (btscan->pdata->kpinterface->prefs->FetchOpt("PLUGIN_BTSCAN_SHOW") == "true" || btscan->pdata->kpinterface->prefs->FetchOpt("PLUGIN_BTSCAN_SHOW") == "") { btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SHOW", "false", 1); btscan->btdevlist->Hide(); btscan->menu->DisableMenuItem(btscan->mi_sort_bdaddr); btscan->menu->DisableMenuItem(btscan->mi_sort_bdname); btscan->menu->DisableMenuItem(btscan->mi_sort_bdclass); btscan->menu->DisableMenuItem(btscan->mi_sort_firsttime); btscan->menu->DisableMenuItem(btscan->mi_sort_lasttime); btscan->menu->DisableMenuItem(btscan->mi_sort_packets); btscan->menu->SetMenuItemChecked(btscan->mi_showbtscan, 0); } else { btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SHOW", "true", 1); btscan->btdevlist->Show(); btscan->menu->EnableMenuItem(btscan->mi_sort_bdaddr); btscan->menu->EnableMenuItem(btscan->mi_sort_bdname); btscan->menu->EnableMenuItem(btscan->mi_sort_bdclass); btscan->menu->EnableMenuItem(btscan->mi_sort_firsttime); btscan->menu->EnableMenuItem(btscan->mi_sort_lasttime); btscan->menu->EnableMenuItem(btscan->mi_sort_packets); btscan->menu->SetMenuItemChecked(btscan->mi_showbtscan, 1); } return; } void Btscan_sort_menu_cb(MENUITEM_CB_PARMS) { btscan_data *btscan = (btscan_data *) auxptr; btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdaddr, 0); btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdname, 0); btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdclass, 0); btscan->menu->SetMenuItemChecked(btscan->mi_sort_firsttime, 0); btscan->menu->SetMenuItemChecked(btscan->mi_sort_lasttime, 0); btscan->menu->SetMenuItemChecked(btscan->mi_sort_packets, 0); if (menuitem == btscan->mi_sort_bdaddr) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdaddr, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "bdaddr", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_bdaddr; } else if (menuitem == btscan->mi_sort_bdname) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdname, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "bdname", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_bdname; } else if (menuitem == btscan->mi_sort_bdclass) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_bdclass, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "bdclass", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_bdclass; } else if (menuitem == btscan->mi_sort_firsttime) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_firsttime, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "firsttime", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_firsttime; } else if (menuitem == btscan->mi_sort_lasttime) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_lasttime, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "lasttime", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_lasttime; } else if (menuitem == btscan->mi_sort_packets) { btscan->menu->SetMenuItemChecked(btscan->mi_sort_packets, 1); btscan->pdata->kpinterface->prefs->SetOpt("PLUGIN_BTSCAN_SORT", "packets", globalreg->timestamp.tv_sec); btscan->sort_type = btscan_sort_packets; } } void BtscanProtoBTSCANDEV(CLIPROTO_CB_PARMS) { btscan_data *btscan = (btscan_data *) auxptr; if (proto_parsed->size() < btscan->asm_btscandev_num) { _MSG("Invalid BTSCANDEV sentence from server", MSGFLAG_INFO); return; } int fnum = 0; btscan_network *btn = NULL; mac_addr ma; ma = mac_addr((*proto_parsed)[fnum++].word); if (ma.error) { return; } map::iterator bti; string tstr; unsigned int tuint; float tfloat; unsigned long tulong; if ((bti = btscan->btdev_map.find(ma)) == btscan->btdev_map.end()) { btn = new btscan_network; btn->bd_addr = ma; btscan->btdev_map[ma] = btn; btscan->btdev_vec.push_back(btn); } else { btn = bti->second; } tstr = MungeToPrintable((*proto_parsed)[fnum++].word); if (btn->bd_name != "" && btn->bd_name != tstr) { // alert on BT dev name change? } btn->bd_name = tstr; tstr = MungeToPrintable((*proto_parsed)[fnum++].word); if (btn->bd_class != "" && btn->bd_class != tstr) { // Alert on BT dev class change? } btn->bd_class = tstr; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { return; } btn->first_time = tuint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { return; } btn->last_time = tuint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { return; } btn->packets = tuint; // Only apply fixed value if we weren't before, never degrade if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { return; } if (btn->gpsdata.gps_valid == 0) btn->gpsdata.gps_valid = tuint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.min_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.min_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.min_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.min_spd = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.max_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.max_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.max_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.max_spd = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.aggregate_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.aggregate_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) return; btn->gpsdata.aggregate_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%lu", &tulong) != 1) return; btn->gpsdata.aggregate_points = tulong; } void BtscanCliConfigured(CLICONF_CB_PARMS) { btscan_data *btscan = (btscan_data *) auxptr; // Wipe the scanlist btscan->btdevlist->Clear(); if (kcli->RegisterProtoHandler("BTSCANDEV", btscan->asm_btscandev_fields, BtscanProtoBTSCANDEV, auxptr) < 0) { _MSG("Could not register BTSCANDEV protocol with remote server", MSGFLAG_ERROR); globalreg->panel_interface->RaiseAlert("No BTSCAN protocol", "The BTSCAN UI was unable to register the required\n" "BTSCANDEV protocol. Either it is unavailable\n" "(you didn't load the BTSCAN server plugin) or you\n" "are using an older server plugin.\n"); return; } } void BtscanCliAdd(KPI_ADDCLI_CB_PARMS) { if (add == 0) return; netcli->AddConfCallback(BtscanCliConfigured, 1, auxptr); } int BtscanTimer(TIMEEVENT_PARMS) { btscan_data *btscan = (btscan_data *) parm; // This isn't efficient at all.. but pull the current line, re-sort the // data vector, clear the display, recreate the strings in the table, // re-insert them, and reset the position to the stored one vector current_row = btscan->btdevlist->GetSelectedData(); mac_addr current_bdaddr; if (current_row.size() >= 1) current_bdaddr = mac_addr(current_row[0]); vector add_row; switch (btscan->sort_type) { case btscan_sort_bdaddr: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Bdaddr()); break; case btscan_sort_bdname: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Name()); break; case btscan_sort_bdclass: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Class()); break; case btscan_sort_firsttime: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Firsttime()); break; case btscan_sort_lasttime: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Lasttime()); break; case btscan_sort_packets: stable_sort(btscan->btdev_vec.begin(), btscan->btdev_vec.end(), Btscan_Sort_Packets()); break; default: break; } btscan->btdevlist->Clear(); for (unsigned int x = 0; x < btscan->btdev_vec.size(); x++) { add_row.clear(); add_row.push_back(btscan->btdev_vec[x]->bd_addr.Mac2String()); add_row.push_back(btscan->btdev_vec[x]->bd_name); add_row.push_back(btscan->btdev_vec[x]->bd_class); add_row.push_back(IntToString(btscan->btdev_vec[x]->packets)); btscan->btdevlist->AddRow(x, add_row); if (btscan->btdev_vec[x]->bd_addr == current_bdaddr) btscan->btdevlist->SetSelected(x); } return 1; } int BtscanDevlistCB(COMPONENT_CALLBACK_PARMS) { btscan_data *btscan = (btscan_data *) aux; int selected = 0; if (btscan->btdev_map.size() == 0) { globalreg->panel_interface->RaiseAlert("No BT devices", "No scanned bluetooth devices, can only show details\n" "once a device has been found.\n"); return 1; } if ((selected = btscan->btdevlist->GetSelected()) < 0 || selected > btscan->btdev_vec.size()) { globalreg->panel_interface->RaiseAlert("No BT device selected", "No bluetooth device selected in the BTScan list, can\n" "only show details once a device has been selected.\n"); return 1; } Btscan_Details_Panel *dp = new Btscan_Details_Panel(globalreg, globalreg->panel_interface); dp->SetBtscan(btscan); dp->SetDetailsNet(btscan->btdev_vec[selected]); globalreg->panel_interface->AddPanel(dp); return 1; } int Btscan_Details_ButtonCB(COMPONENT_CALLBACK_PARMS) { ((Btscan_Details_Panel *) aux)->ButtonAction(component); } Btscan_Details_Panel::Btscan_Details_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { SetTitle("BTScan Details"); btdetailt = new Kis_Free_Text(globalreg, this); AddComponentVec(btdetailt, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); btdetailt->Show(); closebutton = new Kis_Button(globalreg, this); closebutton->SetText("Close"); closebutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, Btscan_Details_ButtonCB, this); AddComponentVec(closebutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); closebutton->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Pack_End(btdetailt, 1, 0); vbox->Pack_End(closebutton, 0, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Show(); SetActiveComponent(btdetailt); main_component = vbox; Position(WIN_CENTER(LINES, COLS)); } Btscan_Details_Panel::~Btscan_Details_Panel() { } void Btscan_Details_Panel::DrawPanel() { vector td; int selected; if (btscan == NULL) { td.push_back("BT details panel draw event happened before btscan"); td.push_back("known, something is busted internally, report this"); } else if (btnet == NULL) { td.push_back("No BT network selected"); } else { td.push_back(AlignString("Name: ", ' ', 2, 16) + btnet->bd_name); td.push_back(AlignString("BDAddr: ", ' ', 2, 16) + btnet->bd_addr.Mac2String()); td.push_back(AlignString("Class: ", ' ', 2, 16) + btnet->bd_class); td.push_back(AlignString("Count: ", ' ', 2, 16) + IntToString(btnet->packets)); td.push_back(AlignString("First Seen: ", ' ', 2, 16) + string(ctime((const time_t *) &(btnet->first_time)) + 4).substr(0, 15)); td.push_back(AlignString("Last Seen: ", ' ', 2, 16) + string(ctime((const time_t *) &(btnet->last_time)) + 4).substr(0, 15)); } btdetailt->SetText(td); Kis_Panel::DrawPanel(); } void Btscan_Details_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == closebutton) { globalreg->panel_interface->KillPanel(this); } } void Btscan_Details_Panel::MenuAction(int opt) { } kismet-2013-03-R1b/plugin-btscan/kismet_btscan.cc0000664000175000017500000000730412124602454021362 0ustar dragorndragorn/* This file is part of Kismet This file was derived directly from aircrack-ng, and most of the other files in this directory come, almost unmodified, from that project. For more information about aircrack-ng, visit: http://aircrack-ng.org Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. * If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. * If you do not wish to do so, delete this exception statement from your version. * If you delete this exception statement from all source files in the program, then also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packetsource_linuxbt.h" #include "packet_btscan.h" #include "tracker_btscan.h" #include "dumpfile_btscantxt.h" GlobalRegistry *globalreg = NULL; int pack_comp_btscan; int btscan_unregister(GlobalRegistry *in_globalreg) { return 0; } int btscan_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; globalreg->sourcetracker->AddChannelList("LINUXBTSCAN:0"); #ifdef USE_PACKETSOURCE_LINUXBT if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_LinuxBT(globalreg)) < 0 || globalreg->fatal_condition) return -1; #endif pack_comp_btscan = globalreg->packetchain->RegisterPacketComponent("BTSCAN"); // Tracker Tracker_BTScan *trackbtscan = new Tracker_BTScan(globalreg); Dumpfile_Btscantxt *bttxt = new Dumpfile_Btscantxt(globalreg); bttxt->SetVolatile(1); bttxt->SetTracker(trackbtscan); return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "BTSCAN"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "Active Bluetooth scanning plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = btscan_register; data->plugin_unregister = btscan_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } kismet-2013-03-R1b/plugin-btscan/packetsource_linuxbt.cc0000664000175000017500000001763212124602454022776 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef SYS_LINUX #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packetsource_linuxbt.h" #include "packet_btscan.h" PacketSource_LinuxBT::PacketSource_LinuxBT(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { thread_active = 0; hci_dev_id = -1; hci_dev = -1; fake_fd[0] = -1; fake_fd[1] = -1; pending_packet = 0; bt_scan_delay = 1; bt_scan_time = 4; linuxbt_packet_id = globalreg->packetchain->RegisterPacketComponent("BTSCAN"); ParseOptions(in_opts); } PacketSource_LinuxBT::~PacketSource_LinuxBT() { CloseSource(); } int PacketSource_LinuxBT::ParseOptions(vector *in_opts) { KisPacketSource::ParseOptions(in_opts); if (FetchOpt("scandelay", in_opts) != "") { if (sscanf(FetchOpt("scandelay", in_opts).c_str(), "%d", &bt_scan_delay) != 1) { _MSG("BTSCAN device " + interface + " invalid scandelay= option, expected " "number in seconds.", MSGFLAG_ERROR); return -1; } _MSG("BTSCAN device " + interface + " delaying " + IntToString(bt_scan_delay) + " seconds between initiating scans.", MSGFLAG_INFO); } return 1; } int PacketSource_LinuxBT::AutotypeProbe(string in_device) { if (hci_devid(in_device.c_str()) >= 0) { type = "BTSCAN"; return 1; } return 0; } // Capture thread to fake async io void *linuxbt_cap_thread(void *arg) { PacketSource_LinuxBT *linuxbt = (PacketSource_LinuxBT *) arg; /* Clear the thread sigmask so we don't catch sigterm weirdly */ sigset_t sset; sigfillset(&sset); pthread_sigmask(SIG_BLOCK, &sset, NULL); char hci_name[KIS_LINUXBT_NAME_MAX]; char hci_class[KIS_LINUXBT_CLASS_MAX]; inquiry_info *hci_inq = NULL; int hci_num_dev = 0; // printf("debug - cap thread\n"); while (linuxbt->thread_active > 0) { // printf("debug - thread active, top of loop\n"); // Lock the device, do a blocking read of info, then sleep (if any) // printf("debug - locking device lock\n"); pthread_mutex_lock(&(linuxbt->device_lock)); if ((hci_num_dev = hci_inquiry(linuxbt->hci_dev_id, linuxbt->bt_scan_time, 100, NULL, &hci_inq, 0)) <= 0) { // printf("debug - hci inq failed out\n"); pthread_mutex_unlock(&(linuxbt->device_lock)); sleep(linuxbt->bt_scan_delay); continue; } for (int x = 0; x < hci_num_dev; x++) { memset(hci_name, 0, KIS_LINUXBT_NAME_MAX); if ((hci_read_remote_name(linuxbt->hci_dev, &(hci_inq + x)->bdaddr, KIS_LINUXBT_NAME_MAX, hci_name, 250000)) < 0) { // printf("debug - hci read remote failed out\n"); continue; } // Lock the queue, throw away if we have more than 100 records pending in // the queue that haven't been handled, and raise the FD high if we need // to, to get Poll() to start paying attention to us pthread_mutex_lock(&(linuxbt->packet_lock)); if (linuxbt->packet_queue.size() > 100) { pthread_mutex_unlock(&(linuxbt->packet_lock)); continue; } struct PacketSource_LinuxBT::linuxbt_pkt *rpkt = new PacketSource_LinuxBT::linuxbt_pkt; char classbuf[8]; uint8_t swapmac[6]; for (unsigned int s = 0; s < 6; s++) { swapmac[s] = (hci_inq + x)->bdaddr.b[5 - s]; } rpkt->bd_name = string(hci_name); rpkt->bd_addr = mac_addr(swapmac); snprintf(classbuf, 6, "%2.2x%2.2x%2.2x", (hci_inq + x)->dev_class[2], (hci_inq + x)->dev_class[1], (hci_inq + x)->dev_class[0]); rpkt->bd_class = "0x" + string(classbuf); linuxbt->packet_queue.push_back(rpkt); if (linuxbt->pending_packet == 0) { linuxbt->pending_packet = 1; write(linuxbt->fake_fd[1], rpkt, 1); } pthread_mutex_unlock(&(linuxbt->packet_lock)); } sleep(linuxbt->bt_scan_delay); // printf("debug - unlocking device lock\n"); pthread_mutex_unlock(&(linuxbt->device_lock)); } linuxbt->thread_active = -1; close(linuxbt->fake_fd[1]); linuxbt->fake_fd[1] = -1; pthread_exit((void *) 0); } int PacketSource_LinuxBT::OpenSource() { if ((hci_dev_id = hci_devid(interface.c_str())) < 0) { _MSG("Linux BTSCAN '" + name + "' failed to open device '" + interface + "': " + "Invalid bluetooth device", MSGFLAG_ERROR); return 0; } if ((hci_dev = hci_open_dev(hci_dev_id)) < 0) { _MSG("Linux BTSCAN '" + name + "' failed to open device '" + interface + "': " + string(strerror(errno)), MSGFLAG_ERROR); return 0; } /* Initialize the pipe, mutex, and reading thread */ if (pipe(fake_fd) < 0) { _MSG("Linux BTSCAN '" + name + "' failed to make a pipe() (this is really " "weird): " + string(strerror(errno)), MSGFLAG_ERROR); hci_dev_id = -1; return 0; } if (pthread_mutex_init(&packet_lock, NULL) < 0 || pthread_mutex_init(&device_lock, NULL) < 0) { _MSG("Linux BTSCAN '" + name + "' failed to initialize pthread mutex: " + string(strerror(errno)), MSGFLAG_ERROR); hci_dev_id = -1; return 0; } /* Launch a capture thread */ thread_active = 1; pthread_create(&cap_thread, NULL, linuxbt_cap_thread, this); return 1; } int PacketSource_LinuxBT::CloseSource() { void *ret; if (thread_active > 0) { // Tell the thread to die thread_active = 0; // Kill it // printf("debug - thread cancel\n"); pthread_cancel(cap_thread); // Grab it back // printf("debug - thread join\n"); pthread_join(cap_thread, &ret); // Kill the mutexes pthread_mutex_destroy(&device_lock); pthread_mutex_destroy(&packet_lock); } if (hci_dev >= 0) hci_close_dev(hci_dev); hci_dev = -1; if (fake_fd[0] >= 0) { close(fake_fd[0]); fake_fd[0] = -1; } if (fake_fd[1] >= 0) { close(fake_fd[1]); fake_fd[1] = -1; } // printf("debug - done closing source\n"); return 1; } int PacketSource_LinuxBT::FetchDescriptor() { // This is as good a place as any to catch a failure if (thread_active < 0) { _MSG("Linux BTSCAN '" + name + "' capture thread failed: " + thread_error, MSGFLAG_INFO); CloseSource(); return -1; } return fake_fd[0]; } int PacketSource_LinuxBT::Poll() { char rx; // Consume the junk byte we used to raise the FD high read(fake_fd[0], &rx, 1); pthread_mutex_lock(&packet_lock); pending_packet = 0; for (unsigned int x = 0; x < packet_queue.size(); x++) { kis_packet *newpack = globalreg->packetchain->GeneratePacket(); newpack->ts.tv_sec = globalreg->timestamp.tv_sec; newpack->ts.tv_usec = globalreg->timestamp.tv_usec; btscan_packinfo *pi = new btscan_packinfo; pi->bd_name = packet_queue[x]->bd_name; pi->bd_class = packet_queue[x]->bd_class; pi->bd_addr = packet_queue[x]->bd_addr; newpack->insert(linuxbt_packet_id, pi); // printf("debug - got BT device %s %s %s\n", pi->bd_addr.Mac2String().c_str(), pi->bd_name.c_str(), pi->bd_class.c_str()); num_packets++; globalreg->packetchain->ProcessPacket(newpack); // Delete the packet queue delete packet_queue[x]; } // Flush the queue packet_queue.clear(); // printf("debug - packet queue cleared %d\n", packet_queue.size()); pthread_mutex_unlock(&packet_lock); return 1; } #endif kismet-2013-03-R1b/plugin-btscan/dumpfile_btscantxt.cc0000664000175000017500000001042412124602454022430 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "dumpfile_btscantxt.h" Dumpfile_Btscantxt::Dumpfile_Btscantxt() { fprintf(stderr, "FATAL OOPS: Dumpfile_Nettxt called with no globalreg\n"); exit(1); } Dumpfile_Btscantxt::Dumpfile_Btscantxt(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; txtfile = NULL; tracker = NULL; type = "btscantxt"; if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Config file missing before Dumpfile_Btscantxt\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("btscantxt")) == "" || globalreg->fatal_condition) { return; } if ((txtfile = fopen(fname.c_str(), "w")) == NULL) { _MSG("Failed to open btscantxt log file '" + fname + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } globalreg->RegisterDumpFile(this); _MSG("Opened btscantxt log file '" + fname + "'", MSGFLAG_INFO); } Dumpfile_Btscantxt::~Dumpfile_Btscantxt() { if (txtfile != NULL) Flush(); txtfile = NULL; } int Dumpfile_Btscantxt::Flush() { if (tracker == NULL) { _MSG("Dumpfile_Btscantxt flush called when tracker was missing", MSGFLAG_ERROR); return -1; } if (txtfile != NULL) fclose(txtfile); string tempname = fname + ".temp"; if ((txtfile = fopen(tempname.c_str(), "w")) == NULL) { _MSG("Failed to open temporary btscantxt file for writing: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } fprintf(txtfile, "Kismet (http://www.kismetwireless.net) BTSCAN\n" "%.24s - Kismet %s.%s.%s BTSCAN %s.%s.%s\n" "-----------------\n\n", ctime(&(globalreg->start_time)), globalreg->version_major.c_str(), globalreg->version_minor.c_str(), globalreg->version_tiny.c_str(), globalreg->version_major.c_str(), globalreg->version_minor.c_str(), globalreg->version_tiny.c_str()); int devnum = 1; for (map::iterator x = tracker->tracked_devs.begin(); x != tracker->tracked_devs.end(); ++x) { btscan_network *btnet = x->second; fprintf(txtfile, "BT Device %d: BDADDR %s\n", devnum, btnet->bd_addr.Mac2String().c_str()); fprintf(txtfile, " Class : %s\n", btnet->bd_class.c_str()); fprintf(txtfile, " Name : %s\n", btnet->bd_name.c_str()); fprintf(txtfile, " Seen : %d\n", btnet->packets); string manuf = "Unknown"; if (globalreg->manufdb != NULL) manuf = globalreg->manufdb->LookupOUI(btnet->bd_addr); fprintf(txtfile, " Manuf : %s\n", manuf.c_str()); fprintf(txtfile, " First : %.24s\n", ctime(&(btnet->first_time))); fprintf(txtfile, " Last : %.24s\n", ctime(&(btnet->last_time))); if (btnet->gpsdata.gps_valid) { fprintf(txtfile, " Min Pos : Lat %f Lon %f Alt %f Spd %f\n", btnet->gpsdata.min_lat, btnet->gpsdata.min_lon, btnet->gpsdata.min_alt, btnet->gpsdata.min_spd); fprintf(txtfile, " Max Pos : Lat %f Lon %f Alt %f Spd %f\n", btnet->gpsdata.max_lat, btnet->gpsdata.max_lon, btnet->gpsdata.max_alt, btnet->gpsdata.max_spd); fprintf(txtfile, " Avg Pos : AvgLat %f AvgLon %f AvgAlt %f\n", btnet->gpsdata.aggregate_lat, btnet->gpsdata.aggregate_lon, btnet->gpsdata.aggregate_alt); } fprintf(txtfile, "\n"); devnum++; } fflush(txtfile); fclose(txtfile); txtfile = NULL; if (rename(tempname.c_str(), fname.c_str()) < 0) { _MSG("Failed to rename btscantxt temp file " + tempname + " to " + fname + ": " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } dumped_frames = devnum; return 1; } kismet-2013-03-R1b/plugin-btscan/packetsource_linuxbt.h0000664000175000017500000000741112124602454022632 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_LINUXBT_H__ #define __PACKETSOURCE_LINUXBT_H__ #include #ifdef SYS_LINUX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USE_PACKETSOURCE_LINUXBT #define KIS_LINUXBT_NAME_MAX 16 #define KIS_LINUXBT_CLASS_MAX 9 class PacketSource_LinuxBT : public KisPacketSource { public: PacketSource_LinuxBT() { fprintf(stderr, "FATAL OOPS: Packetsource_Raven()\n"); exit(1); } PacketSource_LinuxBT(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_LinuxBT(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker) { // Use a channel list we assign in the main loader to a single channel, // we're also not hoppable in the Kismet sense tracker->RegisterPacketProto("btscan", this, "LINUXBTSCAN", 0); return 1; } PacketSource_LinuxBT(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_LinuxBT(); virtual int ParseOptions(vector *in_opts); virtual int OpenSource(); virtual int CloseSource(); // We're not, since we're a fake scanning device virtual int FetchChannelCapable() { return 0; } virtual int EnableMonitor() { return 1; } virtual int DisableMonitor() { return 1; } virtual int FetchChannel() { return -1; } virtual int FetchChannelMod() { return -1; } // We don't virtual int SetChannel(unsigned int in_ch) { return 0; }; // We use a fake FD like the raven (plugin-dot15d4) does virtual int FetchDescriptor(); virtual int Poll(); struct linuxbt_pkt { string bd_name; string bd_class; mac_addr bd_addr; }; protected: virtual void FetchRadioData(kis_packet *in_packet) { }; int linuxbt_packet_id; // We spawn a thread to control scanning since the HCI calls are blocking // and take a long time. We pass packets via locking like we do on raven, // if we have a dozen devices in a scan we'll lock and kick them out int thread_active; pthread_t cap_thread; pthread_mutex_t packet_lock, device_lock; int hci_dev_id, hci_dev; // Delay between scans (seconds) int bt_scan_delay; // Time for each scan (unknown - seconds?) int bt_scan_time; // FD pipes int fake_fd[2]; // Packet storage, locked with packet_lock vector packet_queue; // Pending packet, locked with packet_lock int pending_packet; // Error from thread string thread_error; friend void *linuxbt_cap_thread(void *); }; #endif #endif kismet-2013-03-R1b/plugin-btscan/README0000664000175000017500000000543512124602454017110 0ustar dragorndragornKismet-BTSCAN 1. What is Kismet-BTSCAN 2. Caveats 3. Compiling 4. Installing 5. Using 1. What is Kismet-BTSCAN Kismet-BTSCAN is a Kismet plugin which provides basic scan support for Bluetooth, aka 802.15.1. Bluetooth is a (relatively) low-power PAN network protocol for streaming audio, sharing phone data, etc. This is NOT a Bluetooth SNIFFER. Kismet-BTSCAN uses the scan functionality in the bluetooth drivers to find nearby DISCOVERABLE bluetooth devices. It CAN NOT BE USED with 802.11 wi-fi cards, it is a completely different protocol. 2. Caveats This code is currently under development and does not yet provide the full anticipated functionality, however it can display nearby discoverable bluetooth devices. This is NOT A BLUETOOTH SNIFFER. It will NOT find undiscoverable devices. Kismet-BTSCAN uses the built-in scan functionality of the bluetooth devices to query nearby discoverable devices. This CAN NOT capture bluetooth audio streams. It is a scanner only. Currently, Kismet-BTSCAN works only on Linux, however the framework is in place to allow working on other platforms in the future. Kismet-BTSCAN uses ACTIVE SCANNING in your device. This means PACKETS WILL BE SENT. If this is not acceptable, do NOT use Kismet-BTSCAN. 3. Compiling Compiling the Kismet-BTSCAN plugin requires the Kismet source be installed and configured. By default, Kismet-BTSCAN expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-btscan/ KIS_SRC_DIR=/home/foo/src/kismet make 4. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-ptw KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-ptw make userinstall 5. Using Once the plugin is loaded, Kismet will automatically understand capture interfaces which are Linux bluetooth devices. The UI is currently very simplistic, but will be expanded on in the future. To enable scanning on a bluetooth interface, define a capture source in Kismet using that interface (such as 'hci0'). The device will be automatically detected as type 'btscan'. Kismet-BTSCAN cannot log to a pcap file, as individual packets are not captured. It can however log to a text file, enable 'btscantxt' in your logtypes= line in kismet.conf kismet-2013-03-R1b/plugin-btscan/tracker_btscan.cc0000664000175000017500000001302312124602454021514 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "packet_btscan.h" #include "tracker_btscan.h" extern int pack_comp_btscan; enum BTSCANDEV_fields { BTSCANDEV_bdaddr, BTSCANDEV_name, BTSCANDEV_class, BTSCANDEV_firsttime, BTSCANDEV_lasttime, BTSCANDEV_packets, GPS_COMMON_FIELDS(BTSCANDEV), BTSCANDEV_maxfield }; const char *BTSCANDEV_fields_text[] = { "bdaddr", "name", "class", "firsttime", "lasttime", "packets", GPS_COMMON_FIELDS_TEXT, NULL }; int Protocol_BTSCANDEV(PROTO_PARMS) { btscan_network *bt = (btscan_network *) data; ostringstream osstr; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= BTSCANDEV_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case BTSCANDEV_bdaddr: osstr << bt->bd_addr.Mac2String(); break; case BTSCANDEV_firsttime: osstr << bt->first_time; break; case BTSCANDEV_lasttime: osstr << bt->last_time; break; case BTSCANDEV_packets: osstr << bt->packets; break; case BTSCANDEV_name: osstr << "\001" + bt->bd_name + "\001"; break; case BTSCANDEV_class: osstr << "\001" + bt->bd_class + "\001"; break; case BTSCANDEV_gpsfixed: osstr << bt->gpsdata.gps_valid; break; case BTSCANDEV_minlat: osstr << bt->gpsdata.min_lat; break; case BTSCANDEV_maxlat: osstr << bt->gpsdata.max_lat; break; case BTSCANDEV_minlon: osstr << bt->gpsdata.min_lon; break; case BTSCANDEV_maxlon: osstr << bt->gpsdata.max_lon; break; case BTSCANDEV_minalt: osstr << bt->gpsdata.min_alt; break; case BTSCANDEV_maxalt: osstr << bt->gpsdata.max_alt; break; case BTSCANDEV_minspd: osstr << bt->gpsdata.min_spd; break; case BTSCANDEV_maxspd: osstr << bt->gpsdata.max_spd; break; case BTSCANDEV_agglat: osstr << bt->gpsdata.aggregate_lat; break; case BTSCANDEV_agglon: osstr << bt->gpsdata.aggregate_lon; break; case BTSCANDEV_aggalt: osstr << bt->gpsdata.aggregate_alt; break; case BTSCANDEV_aggpoints: osstr <gpsdata.aggregate_points; break; } out_string += osstr.str() + " "; cache->Cache(fnum, osstr.str()); } return 1; } void Protocol_BTSCANDEV_enable(PROTO_ENABLE_PARMS) { ((Tracker_BTScan *) data)->BlitDevices(in_fd); } int btscantracktimer(TIMEEVENT_PARMS) { ((Tracker_BTScan *) parm)->BlitDevices(-1); return 1; } int btscan_chain_hook(CHAINCALL_PARMS) { return ((Tracker_BTScan *) auxdata)->chain_handler(in_pack); } Tracker_BTScan::Tracker_BTScan(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; globalreg->packetchain->RegisterHandler(&btscan_chain_hook, this, CHAINPOS_CLASSIFIER, 0); BTSCANDEV_ref = globalreg->kisnetserver->RegisterProtocol("BTSCANDEV", 0, 1, BTSCANDEV_fields_text, &Protocol_BTSCANDEV, &Protocol_BTSCANDEV_enable, this); timer_ref = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &btscantracktimer, this); } int Tracker_BTScan::chain_handler(kis_packet *in_pack) { btscan_packinfo *bti = (btscan_packinfo *) in_pack->fetch(pack_comp_btscan); if (bti == NULL) return 0; btscan_network *btnet = NULL; map::iterator titr = tracked_devs.find(bti->bd_addr); if (titr == tracked_devs.end()) { btnet = new btscan_network(); btnet->first_time = globalreg->timestamp.tv_sec; btnet->bd_addr = bti->bd_addr; btnet->bd_name = MungeToPrintable(bti->bd_name); btnet->bd_class = MungeToPrintable(bti->bd_class); tracked_devs[bti->bd_addr] = btnet; _MSG("Detected new bluetooth device \"" + btnet->bd_name + "\", MAC " + btnet->bd_addr.Mac2String() + " class " + btnet->bd_class, MSGFLAG_INFO); } else { btnet = titr->second; } kis_gps_packinfo *gpsinfo = (kis_gps_packinfo *) in_pack->fetch(_PCM(PACK_COMP_GPS)); if (gpsinfo != NULL && gpsinfo->gps_fix) { btnet->gpsdata += gpsinfo; } btnet->last_time = globalreg->timestamp.tv_sec; btnet->packets++; btnet->dirty = 1; return 1; } void Tracker_BTScan::BlitDevices(int in_fd) { map::iterator x; for (x = tracked_devs.begin(); x != tracked_devs.end(); x++) { kis_protocol_cache cache; if (in_fd == -1) { if (x->second->dirty == 0) continue; x->second->dirty = 0; if (globalreg->kisnetserver->SendToAll(BTSCANDEV_ref, (void *) x->second) < 0) break; } else { if (globalreg->kisnetserver->SendToClient(in_fd, BTSCANDEV_ref, (void *) x->second, &cache) < 0) break; } } } kismet-2013-03-R1b/plugin-btscan/dumpfile_btscantxt.h0000664000175000017500000000251312124602454022272 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_BTSCANTXT_H__ #define __DUMPFILE_BTSCANTXT_H__ #include "config.h" #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "dumpfile.h" #include "tracker_btscan.h" // Net txt bulk logger class Dumpfile_Btscantxt : public Dumpfile { public: Dumpfile_Btscantxt(); Dumpfile_Btscantxt(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Btscantxt(); void SetTracker(Tracker_BTScan *in_tracker) { tracker = in_tracker; } virtual int Flush(); protected: FILE *txtfile; Tracker_BTScan *tracker; }; #endif /* __dump... */ kismet-2013-03-R1b/scripts/0000775000175000017500000000000012124602454015142 5ustar dragorndragornkismet-2013-03-R1b/scripts/kismet.in0000775000175000017500000000040212124602454016765 0ustar dragorndragorn#!/bin/sh prefix=@prefix@ exec_prefix=@exec_prefix@ ETC=@sysconfdir@ BIN=@bindir@ oargs=$* until test -z "$1"; do if test "$1" = "--help" -o "$1" = "-h"; then exec ${BIN}/kismet_server --help fi shift done exec ${BIN}/kismet_client $client $oargs kismet-2013-03-R1b/scripts/gpsmap-helper-earthamaps0000775000175000017500000000512012124602454021755 0ustar dragorndragorn#!/usr/bin/perl -w =begin comment info +-----------------------------------------------------------------------------+ | Copyright 2004, Ryan W. Maple | $Id: gpsmap-helper-earthamaps,v 1.1 2004/03/19 20:36:00 dragorn Exp $ | | This script 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 2 of the License, or (at your option) any later | version. | | Ryan W. Maple | | By using this script you agree to the terms and conditions of Earthamaps.com | +-----------------------------------------------------------------------------+ =end comment info =cut # use perl; use HTTP::Cookies; use LWP; use strict; # # Local prototypes. # sub USAGE(); sub init_cookie_jar($); # # Constants # use constant DEBUG => 0; use constant EARTHAMAP_FORMAT => 'http://esmap1.earthamaps.com:80/map-engine/NetMap.dll?MFCISAPICommand=GeoDraw&maglevel=%d&latitude=%f&longitude=%f&session=%s&width=%d&height=%d&dataID=(null)'; # # Read our arguments. # my $mapname = shift || USAGE(); my $lat = shift || USAGE(); my $long = shift || USAGE(); my $width = shift || 1280; my $height = shift || 1024; my $mag = shift || 12; # # Instantiate our browser (LWP::UserAgent object), and initialize # our cookie jar. # my $browser = new LWP::UserAgent; init_cookie_jar($browser); # # Do our initial GET for our cookie... yummy. # my $response = $browser->get('http://www.earthamaps.com/'); # # Extract the x-meta-mapservername header -- we'll need to pass it as # 'session' in our second GET, and build up our second $url. # my $tmp = $response->{'_headers'}->{'x-meta-mapservername'}; my ($session) = ($tmp =~ m/session=([^\&]+)\&/); my $url = sprintf(EARTHAMAP_FORMAT, $mag, $lat, $long, $session, $width, $height); # # Get the map and store in $mapname. # print "Fetching URL: $url\n" if (DEBUG); $response = $browser->get($url); open OUT, ">$mapname"; print OUT $response->{'_content'}; close OUT; # # Exit quietly. # print "Wrote: $mapname\n" if (DEBUG); exit 0; ################################################################################ sub USAGE() { print "Usage: $0 [ ]\n"; exit 0; } ################################################################################ sub init_cookie_jar($) { my $ref = shift; my $cj = HTTP::Cookies->new( 'file' => './lwp_cookies.dat', 'autosave' => 1, ); return $ref->cookie_jar($cj); } kismet-2013-03-R1b/local_ieee80211_radiotap.h0000664000175000017500000002120312124602454020162 0ustar dragorndragorn/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ /* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #ifndef IEEE80211RADIOTAP_H #define IEEE80211RADIOTAP_H /* Kluge the radiotap linktype for now if we don't have it */ #ifndef LNX_ARPHRD_IEEE80211_RADIOTAP #define LNX_ARPHRD_IEEE80211_RADIOTAP 803 #endif /* Radiotap header version (from official NetBSD feed) */ #define IEEE80211RADIOTAP_VERSION "1.5" /* Base version of the radiotap packet header data */ #define PKTHDR_RADIOTAP_VERSION 0 /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even * units given for some fields) nor easily extensible. * * I suggest the following extensible radio capture format. It is * based on a bitmap indicating which fields are present. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. */ /* XXX tcpdump/libpcap do not tolerate variable-length headers, * yet, so we pad every radiotap header to 64 bytes. Ugh. */ #define IEEE80211_RADIOTAP_HDRLEN 64 /* The radio capture header precedes the 802.11 header. */ struct ieee80211_radiotap_header { u_int8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ u_int8_t it_pad; u_int16_t it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ u_int32_t it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. * Additional extensions are made * by setting bit 31. */ }; /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS u_int16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s * * Tx/Rx data rate * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_LOCK_QUALITY u_int16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_FCS u_int32_t data * * FCS from frame in network byte order. */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, IEEE80211_RADIOTAP_FLAGS = 1, IEEE80211_RADIOTAP_RATE = 2, IEEE80211_RADIOTAP_CHANNEL = 3, IEEE80211_RADIOTAP_FHSS = 4, IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, IEEE80211_RADIOTAP_LOCK_QUALITY = 7, IEEE80211_RADIOTAP_TX_ATTENUATION = 8, IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, IEEE80211_RADIOTAP_DBM_TX_POWER = 10, IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, IEEE80211_RADIOTAP_EXT = 31, }; /* Channel flags. */ #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received * during CFP */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received * with short * preamble */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received * with WEP encryption */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received * with fragmentation */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between * 802.11 header and payload * (to 32-bit boundary) */ /* Ugly macro to convert literal channel numbers into their mhz equivalents * There are certianly some conditions that will break this (like feeding it '30') * but they shouldn't arise since nothing talks on channel 30. */ #define ieee80211chan2mhz(x) \ (((x) <= 14) ? \ (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ ((x) + 1000) * 5) #endif /* IEEE80211_RADIOTAP_H */ kismet-2013-03-R1b/packetsource_macusb.h0000664000175000017500000000471112124602454017651 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_MACUSB_H__ #define __PACKETSOURCE_MACUSB_H__ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(SYS_DARWIN) #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "ifcontrol.h" #include "packetsource_pcap.h" #include "kis_ppi.h" #define USE_PACKETSOURCE_MACUSB class PacketSource_MacUSB : public PacketSource_Pcap { public: PacketSource_MacUSB() { fprintf(stderr, "FATAL OOPS: Packetsource_MacUSB() called\n"); exit(1); } PacketSource_MacUSB(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } // This should return a new object of its own subclass type virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_MacUSB(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_MacUSB(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_MacUSB() { } // virtual int OpenSource(); // virtual int Poll(); virtual int FetchChannelCapable() { return 1; } // In the future maybe we'll start the source automatically? virtual int EnableMonitor() { return 0; } virtual int DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_SILENCE; } // In the future we'll have a channel control mechanism virtual int SetChannel(unsigned int in_ch) { return 0; } virtual int HopNextChannel() { return 0; } protected: // Do nothing here, we don't have an independent radio data fetch, // we're just filling in the virtual virtual void FetchRadioData(kis_packet *in_packet) { }; }; #endif #endif kismet-2013-03-R1b/kis_panel_windows.cc0000664000175000017500000033161412124602454017511 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include #include #include #include #include #include #include #include #include "kis_panel_widgets.h" #include "kis_panel_frontend.h" #include "kis_panel_windows.h" #include "kis_panel_details.h" #include "kis_panel_preferences.h" #include "soundcontrol.h" int MenuActivateCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Main_Panel *) aux)->MenuAction(status); return 1; } void KisMainPanel_AddCli(KPI_ADDCLI_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->NetClientAdd(netcli, add); } void KisMainPanel_Configured(CLICONF_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->NetClientConfigure(kcli, recon); } void KisMainPanel_INFO(CLIPROTO_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->Proto_INFO(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisMainPanel_GPS(CLIPROTO_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->Proto_GPS(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisMainPanel_BATTERY(CLIPROTO_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->Proto_BATTERY(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisMainPanel_ALERT(CLIPROTO_CB_PARMS) { ((Kis_Main_Panel *) auxptr)->Proto_ALERT(globalreg, proto_string, proto_parsed, srccli, auxptr); } int NetlistActivateCB(COMPONENT_CALLBACK_PARMS) { Kis_NetDetails_Panel *dp = new Kis_NetDetails_Panel(globalreg, ((Kis_Main_Panel *) aux)->FetchPanelInterface()); dp->Position(WIN_CENTER(LINES, COLS)); ((Kis_Main_Panel *) aux)->FetchPanelInterface()->AddPanel(dp); return 1; } int ClilistActivateCB(COMPONENT_CALLBACK_PARMS) { Kis_ClientDetails_Panel *dp = new Kis_ClientDetails_Panel(globalreg, ((Kis_Main_Panel *) aux)->FetchPanelInterface()); dp->SetClientlist((Kis_Clientlist *) component); dp->Position(WIN_CENTER(LINES, COLS)); ((Kis_Main_Panel *) aux)->FetchPanelInterface()->AddPanel(dp); return 1; } const char *gps_fields[] = { "connected", "fix", "lat", "lon", "alt", "spd", "heading", NULL }; Kis_Main_Panel::Kis_Main_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, MenuActivateCB, this); mn_file = menu->AddMenu("Kismet", 0); mi_startserver = menu->AddMenuItem("Start Server...", mn_file, 'S'); mi_serverconsole = menu->AddMenuItem("Server Console...", mn_file, 'c'); menu->AddMenuItem("-", mn_file, 0); mi_connect = menu->AddMenuItem("Connect...", mn_file, 'C'); mi_disconnect = menu->AddMenuItem("Disconnect", mn_file, 'D'); menu->AddMenuItem("-", mn_file, 0); mi_addcard = menu->AddMenuItem("Add Source...", mn_file, 'A'); mi_conf = menu->AddMenuItem("Config Channel...", mn_file, 'L'); menu->AddMenuItem("-", mn_file, 0); mn_plugins = menu->AddSubMenuItem("Plugins", mn_file, 'x'); mi_addplugin = menu->AddMenuItem("Select Plugins...", mn_plugins, 'P'); menu->AddMenuItem("-", mn_plugins, 0); mi_noplugins = menu->AddMenuItem("No plugins loaded...", mn_plugins, 0); menu->DisableMenuItem(mi_noplugins); mn_preferences = menu->AddSubMenuItem("Preferences", mn_file, 'P'); mi_audioprefs = menu->AddMenuItem("Audio...", mn_preferences, 'A'); mi_colorprefs = menu->AddMenuItem("Colors...", mn_preferences, 'C'); mi_clicolprefs = menu->AddMenuItem("Client Columns...", mn_preferences, 'c'); mi_cliextraprefs = menu->AddMenuItem("Client Extras...", mn_preferences, 'E'); mi_gpsprefs = menu->AddMenuItem("GPS...", mn_preferences, 'G'); mi_infoprefs = menu->AddMenuItem("Info Pane...", mn_preferences, 'I'); mi_netcolprefs = menu->AddMenuItem("Network Columns...", mn_preferences, 'n'); mi_netextraprefs = menu->AddMenuItem("Network Extras...", mn_preferences, 'e'); mi_serverprefs = menu->AddMenuItem("Servers...", mn_preferences, 'S'); mi_startprefs = menu->AddMenuItem("Startup & Shutdown...", mn_preferences, 's'); mi_warnprefs = menu->AddMenuItem("Warnings...", mn_preferences, 'W'); menu->AddMenuItem("-", mn_file, 0); mi_quit = menu->AddMenuItem("Quit", mn_file, 'Q'); menu->EnableMenuItem(mi_connect); menu->DisableMenuItem(mi_disconnect); connect_enable = 1; mn_sort = menu->AddMenu("Sort", 0); mi_sort_auto = menu->AddMenuItem("Auto-fit", mn_sort, 'a'); menu->AddMenuItem("-", mn_sort, 0); mi_sort_type = menu->AddMenuItem("Type", mn_sort, 't'); mi_sort_chan = menu->AddMenuItem("Channel", mn_sort, 'c'); mi_sort_crypt = menu->AddMenuItem("Encryption", mn_sort, 'e'); mi_sort_first = menu->AddMenuItem("First Seen", mn_sort, 'f'); mi_sort_first_d = menu->AddMenuItem("First Seen (descending)", mn_sort, 'F'); mi_sort_last = menu->AddMenuItem("Latest Seen", mn_sort, 'l'); mi_sort_last_d = menu->AddMenuItem("Latest Seen (descending)", mn_sort, 'L'); mi_sort_bssid = menu->AddMenuItem("BSSID", mn_sort, 'b'); mi_sort_ssid = menu->AddMenuItem("SSID", mn_sort, 's'); mi_sort_sdbm = menu->AddMenuItem("Signal", mn_sort, 'S'); mi_sort_packets = menu->AddMenuItem("Packets", mn_sort, 'p'); mi_sort_packets_d = menu->AddMenuItem("Packets (descending)", mn_sort, 'P'); menu->SetMenuItemCheckSymbol(mi_sort_auto, '*'); menu->SetMenuItemCheckSymbol(mi_sort_type, '*'); menu->SetMenuItemCheckSymbol(mi_sort_chan, '*'); menu->SetMenuItemCheckSymbol(mi_sort_crypt, '*'); menu->SetMenuItemCheckSymbol(mi_sort_first, '*'); menu->SetMenuItemCheckSymbol(mi_sort_first_d, '*'); menu->SetMenuItemCheckSymbol(mi_sort_last, '*'); menu->SetMenuItemCheckSymbol(mi_sort_last_d, '*'); menu->SetMenuItemCheckSymbol(mi_sort_bssid, '*'); menu->SetMenuItemCheckSymbol(mi_sort_ssid, '*'); menu->SetMenuItemCheckSymbol(mi_sort_sdbm, '*'); menu->SetMenuItemCheckSymbol(mi_sort_packets, '*'); menu->SetMenuItemCheckSymbol(mi_sort_packets_d, '*'); mn_view = menu->AddMenu("View", 0); mi_shownetworks = menu->AddMenuItem("Network List", mn_view, 'n'); mi_showclients = menu->AddMenuItem("Client List", mn_view, 'c'); mi_showgps = menu->AddMenuItem("GPS Data", mn_view, 'g'); mi_showbattery = menu->AddMenuItem("Battery", mn_view, 'b'); mi_showsummary = menu->AddMenuItem("General Info", mn_view, 'S'); mi_showstatus = menu->AddMenuItem("Status", mn_view, 's'); mi_showpps = menu->AddMenuItem("Packet Graph", mn_view, 'p'); mi_showsources = menu->AddMenuItem("Source Info", mn_view, 'C'); mn_windows = menu->AddMenu("Windows", 0); mi_netdetails = menu->AddMenuItem("Network Details...", mn_windows, 'd'); mi_clientlist = menu->AddMenuItem("Client List...", mn_windows, 'l'); mi_addnote = menu->AddMenuItem("Network Note...", mn_windows, 'N'); mi_chandetails = menu->AddMenuItem("Channel Details...", mn_windows, 'c'); mi_gps = menu->AddMenuItem("GPS Details...", mn_windows, 'g'); mi_alerts = menu->AddMenuItem("Alerts...", mn_windows, 'a'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); mn_sort_appended = mn_view_appended = 0; // Make a hbox to hold the network list and additional info widgets, // and the vertical stack of optional widgets hbox = new Kis_Panel_Packbox(globalreg, this); hbox->SetPackH(); hbox->SetHomogenous(0); hbox->SetSpacing(1); hbox->Show(); // Make a vbox to hold the hbox we just made, and the status text vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); // Make the network pack box which holds the network widget and the // extra info line widget netbox = new Kis_Panel_Packbox(globalreg, this); netbox->SetPackV(); netbox->SetSpacing(0); netbox->SetHomogenous(0); netbox->SetName("KIS_MAIN_NETBOX"); netbox->Show(); // Make the one-line horizontal box which holds GPS, battery, etc linebox = new Kis_Panel_Packbox(globalreg, this); linebox->SetPackH(); linebox->SetSpacing(1); linebox->SetHomogenous(0); linebox->SetName("KIS_MAIN_LINEBOX"); linebox->SetPreferredSize(0, 1); linebox->Show(); // Make the vertical box holding things like the # of networks optbox = new Kis_Panel_Packbox(globalreg, this); optbox->SetPackV(); optbox->SetSpacing(1); optbox->SetHomogenous(0); optbox->SetName("KIS_MAIN_OPTBOX"); optbox->SetPreferredSize(10, 0); optbox->Show(); statustext = new Kis_Status_Text(globalreg, this); statuscli = new KisStatusText_Messageclient(globalreg, statustext); globalreg->messagebus->RegisterClient(statuscli, MSGFLAG_ALL); // We only want 5 lines of status text statustext->SetPreferredSize(0, 5); statustext->SetName("KIS_MAIN_STATUS"); statustext->Show(); netlist = new Kis_Netlist(globalreg, this); netlist->SetName("KIS_MAIN_NETLIST"); netlist->Show(); netlist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, NetlistActivateCB, this); clientlist = new Kis_Clientlist(globalreg, this); clientlist->SetName("KIS_MAIN_CLIENTLIST"); clientlist->FollowDNG(1); clientlist->Show(); clientlist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ClilistActivateCB, this); // Set up the packet rate graph as over/under linked to the // packets per second packetrate = new Kis_IntGraph(globalreg, this); packetrate->SetName("PPS_GRAPH"); packetrate->SetPreferredSize(0, 8); packetrate->SetScale(0, 0); packetrate->SetInterpolation(1); packetrate->SetMode(1); packetrate->Show(); packetrate->AddExtDataVec("Packets", 4, "graph_pps", "yellow,yellow", ' ', ' ', 1, &pps); packetrate->AddExtDataVec("Data", 4, "graph_datapps", "red,red", ' ', ' ', -1, &datapps); for (unsigned int x = 0; x < 50; x++) { pps.push_back(0); datapps.push_back(0); } lastpackets = lastdata = 0; infobits = new Kis_Info_Bits(globalreg, this); infobits->SetName("KIS_MAIN_INFOBITS"); infobits->Show(); optbox->Pack_End(infobits, 1, 0); sourceinfo = new Kis_Free_Text(globalreg, this); sourceinfo->SetName("KIS_MAIN_SOURCEINFO"); sourceinfo->SetAlignment(1); optbox->Pack_End(sourceinfo, 0, 0); gpsinfo = new Kis_Free_Text(globalreg, this); gpsinfo->SetName("KIS_MAIN_GPSINFO"); gpsinfo->SetAlignment(1); gpsinfo->SetText("No GPS info (GPS not connected)"); gpsinfo->Show(); linebox->Pack_End(gpsinfo, 0, 0); batteryinfo = new Kis_Free_Text(globalreg, this); batteryinfo->SetName("KIS_MAIN_BATTERY"); batteryinfo->SetAlignment(1); batteryinfo->Show(); linebox->Pack_End(batteryinfo, 0, 0); // Pack our boxes together hbox->Pack_End(netbox, 1, 0); hbox->Pack_End(optbox, 0, 0); netbox->Pack_End(netlist, 1, 0); netbox->Pack_End(clientlist, 1, 0); netbox->Pack_End(linebox, 0, 0); netbox->Pack_End(packetrate, 0, 0); netbox->Pack_End(statustext, 0, 0); vbox->Pack_End(hbox, 1, 0); AddComponentVec(netlist, KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT); AddComponentVec(clientlist, KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); if (kpinterface->prefs->FetchOpt("LOADEDFROMFILE") != "1") { _MSG("Failed to load preferences file, will use defaults", MSGFLAG_INFO); } // Initialize base colors InitColorPref("panel_text_color", "white,black"); InitColorPref("panel_textdis_color", "white,black"); AddColorPref("panel_text_color", "Text"); AddColorPref("panel_textdis_color", "Text-Inactive"); AddColorPref("panel_border_color", "Window Border"); AddColorPref("menu_text_color", "Menu Text"); AddColorPref("menu_disable_color", "Menu Disabled"); AddColorPref("menu_border_color", "Menu Border"); AddColorPref("netlist_header_color", "Netlist Header"); AddColorPref("netlist_normal_color", "Netlist Unencrypted"); AddColorPref("netlist_wep_color", "Netlist WEP"); AddColorPref("netlist_crypt_color", "Netlist Encrypted"); AddColorPref("netlist_group_color", "Netlist Group"); AddColorPref("netlist_decrypt_color", "Netlist Decrypted"); AddColorPref("clientlist_header_color", "Clientlist Header"); AddColorPref("clientlist_normal_color", "Clientlist Unknown"); AddColorPref("clientlist_ap_color", "Clientlist AP"); AddColorPref("clientlist_wireless_color", "Clientlist Wireless"); AddColorPref("clientlist_adhoc_color", "Clientlist Ad-Hoc"); AddColorPref("status_normal_color", "Status Text"); AddColorPref("info_normal_color", "Info Pane"); AddColorPref("graph_pps", "PPS Graph"); AddColorPref("graph_datapps", "PPS Data Graph"); AddColorPref("graph_detail_pps", "Network Packet Graph"); AddColorPref("graph_detail_retrypps", "Network Retry Graph"); AddColorPref("graph_detail_sig", "Network Signal Graph"); UpdateViewMenu(-1); agg_gps_num = TokenNullJoin(&agg_gps_fields, gps_fields); addref = kpinterface->Add_NetCli_AddCli_CB(KisMainPanel_AddCli, (void *) this); SetActiveComponent(netlist); } Kis_Main_Panel::~Kis_Main_Panel() { globalreg->messagebus->RemoveClient(statuscli); kpinterface->Remove_Netcli_AddCli_CB(addref); kpinterface->Remove_All_Netcli_Conf_CB(KisMainPanel_Configured); kpinterface->Remove_All_Netcli_ProtoHandler("INFO", KisMainPanel_INFO, this); kpinterface->Remove_All_Netcli_ProtoHandler("GPS", KisMainPanel_GPS, this); kpinterface->Remove_All_Netcli_ProtoHandler("BATTERY", KisMainPanel_BATTERY, this); kpinterface->Remove_All_Netcli_ProtoHandler("ALERT", KisMainPanel_ALERT, this); } void kmp_prompt_startserver(KIS_PROMPT_CB_PARMS) { if (ok) { Kis_Spawn_Panel *sp = new Kis_Spawn_Panel(globalreg, globalreg->panel_interface); // if (globalreg->panel_interface->prefs->FetchOpt("STARTUP_CONSOLE") == "true" || // globalreg->panel_interface->prefs->FetchOpt("STARTUP_CONSOLE") == "") if (globalreg->panel_interface->prefs->FetchOptBoolean("STARTUP_CONSOLE", 1)) sp->SpawnConsole(1); else sp->SpawnConsole(0); globalreg->panel_interface->QueueModalPanel(sp); } } void kmp_prompt_asroot(KIS_PROMPT_CB_PARMS) { if (check) { globalreg->panel_interface->prefs->SetOpt("STARTUP_WARNROOT", "false", 1); } } void kmp_prompt_greycolor(KIS_PROMPT_CB_PARMS) { if (ok) globalreg->panel_interface->prefs->SetOpt("panel_textdis_color", "grey,black", time(0)); globalreg->panel_interface->prefs->SetOpt("STARTUP_COLOR", "true", time(0)); } void Kis_Main_Panel::Startup() { int initclient = 0; // Save preferences to detect errors kpinterface->SavePreferences(); // Load audio prefs and set up defaults LoadAudioPrefs(); if (kpinterface->prefs->FetchOpt("DEFAULT_HOST") == "") { kpinterface->prefs->SetOpt("DEFAULT_HOST", "localhost", 1); kpinterface->prefs->SetOpt("DEFAULT_PORT", "2501", 1); kpinterface->prefs->SetOpt("AUTOCONNECT", "true", 1); } // if (kpinterface->prefs->FetchOpt("autoconnect") == "true" && if (kpinterface->prefs->FetchOptBoolean("autoconnect", 0) && kpinterface->prefs->FetchOpt("default_host") != "" && kpinterface->prefs->FetchOpt("default_port") != "") { string constr = string("tcp://") + kpinterface->prefs->FetchOpt("default_host") + ":" + kpinterface->prefs->FetchOpt("default_port"); _MSG("Auto-connecting to " + constr, MSGFLAG_INFO); initclient = kpinterface->AddNetClient(constr, 1); } if (kpinterface->prefs->FetchOpt("STARTUP_COLOR") == "") { vector t; Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, kpinterface); kpp->InitColorPref("grey_color", "grey,black"); kpp->InitColorPref("white_color", "white,black"); t.push_back("\004Cwhite_color;Some terminals don't display some colors " "(notably, dark grey)"); t.push_back("correctly. The next line of text should read 'Dark grey text': "); t.push_back("\004Cgrey_color;Dark grey text"); t.push_back("\004Cwhite_color;Is it visible? If you answer 'No', dark grey "); t.push_back("will not be used in the default color scheme. Remember, you "); t.push_back("can always change colors to your taste by going to "); t.push_back("Kismet->Preferences->Colors."); t.push_back(""); kpp->SetTitle("Terminal colors"); kpp->SetCallback(kmp_prompt_greycolor, this); kpp->SetDisplayText(t); kpp->SetButtonText("Yes", "No"); kpinterface->QueueModalPanel(kpp); } // if ((getuid() == 0 || geteuid() == 0) && // (kpinterface->prefs->FetchOpt("STARTUP_WARNROOT") == "" || // kpinterface->prefs->FetchOpt("STARTUP_WARNROOT") == "true")) { if ((getuid() == 0 || geteuid() == 0) && kpinterface->prefs->FetchOptBoolean("STARTUP_WARNROOT", 1)) { vector t; t.push_back("Kismet is running as root"); t.push_back("Kismet was started as root. This isn't the recommended"); t.push_back("way to start Kismet as it can be dangerous -- the risk"); t.push_back("to your system from any programming errors is increased."); t.push_back("See the README section 'SUID INSTALLATION & SECURITY' for"); t.push_back("more information."); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, kpinterface); kpp->SetTitle("Kismet running as root"); kpp->SetDisplayText(t); kpp->SetCheckText("Do not show this warning in the future"); kpp->SetChecked(0); kpp->SetButtonText("OK", ""); kpp->SetCallback(kmp_prompt_asroot, this); kpinterface->QueueModalPanel(kpp); } // If we're supposed to prompt for the server and we haven't successfully // auto-connected to the default... // if ((kpinterface->prefs->FetchOpt("STARTUP_PROMPTSERVER") == "" || // kpinterface->prefs->FetchOpt("STARTUP_PROMPTSERVER") == "true") && // initclient <= 0) { if (kpinterface->prefs->FetchOptBoolean("STARTUP_PROMPTSERVER", 1) && initclient <= 0) { vector t; t.push_back("Automatically start Kismet server?"); t.push_back("Launch Kismet server and connect to it automatically."); t.push_back("If you use a Kismet server started elsewhere, choose"); t.push_back("No and change the Startup preferences."); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, kpinterface); kpp->SetTitle("Start Kismet Server"); kpp->SetDisplayText(t); kpp->SetCallback(kmp_prompt_startserver, this); kpp->SetButtonText("Yes", "No"); kpp->SetDefaultButton(1); kpinterface->QueueModalPanel(kpp); // } else if ((kpinterface->prefs->FetchOpt("STARTUP_SERVER") == "true" || // kpinterface->prefs->FetchOpt("STARTUP_SERVER") == "") && // initclient <= 0) { } else if (kpinterface->prefs->FetchOptBoolean("STARTUP_SERVER", 1) && initclient <= 0) { // fprintf(stderr, "debug - kmp_prompt_startserver\n"); kmp_prompt_startserver(globalreg, 1, -1, this); } } void Kis_Main_Panel::NetClientConfigure(KisNetClient *in_cli, int in_recon) { // Reset the GPS text gpsinfo->SetText("No GPS info (GPS not connected)"); if (in_cli->RegisterProtoHandler("INFO", "packets,llcpackets,rate,networks", KisMainPanel_INFO, this) < 0) { _MSG("Could not register INFO protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("GPS", agg_gps_fields, KisMainPanel_GPS, this) < 0) { _MSG("Could not register GPS protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("BATTERY", "percentage,charging,ac,remaining", KisMainPanel_BATTERY, this) < 0) { _MSG("Could not register BATTERY protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("ALERT", "header", KisMainPanel_ALERT, this) < 0) { _MSG("Could not register ALERT protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } } void Kis_Main_Panel::NetClientAdd(KisNetClient *in_cli, int add) { if (add == 0) return; in_cli->AddConfCallback(KisMainPanel_Configured, 1, this); } void Kis_Main_Panel::LoadAudioPrefs() { // Set up the sound and speech options and fill in all the prefs so they're // in the file in the future if (kpinterface->prefs->FetchOpt("SOUNDBIN") == "") kpinterface->prefs->SetOpt("SOUNDBIN", "play", 1); globalreg->soundctl->SetPlayer(kpinterface->prefs->FetchOpt("SOUNDBIN")); if (kpinterface->prefs->FetchOpt("SPEECHBIN") == "") kpinterface->prefs->SetOpt("SPEECHBIN", "flite", 1); if (kpinterface->prefs->FetchOpt("SPEECHTYPE") == "") kpinterface->prefs->SetOpt("SPEECHTYPE", "raw", 1); globalreg->soundctl->SetSpeaker(kpinterface->prefs->FetchOpt("SPEECHBIN"), kpinterface->prefs->FetchOpt("SPEECHTYPE")); if (kpinterface->prefs->FetchOpt("SPEECHENCODING") == "") kpinterface->prefs->SetOpt("SPEECHENCODING", "spell", 1); globalreg->soundctl->SetSpeechEncode(kpinterface->prefs->FetchOpt("SPEECHENCODING")); if (kpinterface->prefs->FetchOpt("SOUNDENABLE") == "") { // TODO - call "do you want to enable sound" prompt kpinterface->prefs->SetOpt("SOUNDENABLE", "false", 1); } // globalreg->soundctl->SetSoundEnable(StrLower(kpinterface->prefs->FetchOpt("SOUNDENABLE")) == "true"); globalreg->soundctl->SetSoundEnable(kpinterface->prefs->FetchOptBoolean("SOUNDENABLE", 0)); if (kpinterface->prefs->FetchOpt("SPEECHENABLE") == "") { // TOO - call "do you want to enable speech" prompt kpinterface->prefs->SetOpt("SPEECHENABLE", "false", 1); } // globalreg->soundctl->SetSpeechEnable(StrLower(kpinterface->prefs->FetchOpt("SPEECHENABLE")) == "true"); globalreg->soundctl->SetSpeechEnable(kpinterface->prefs->FetchOptBoolean("SPEECHENABLE", 0)); snd_new = snd_packet = snd_gpslock = snd_gpslost = snd_alert = -1; if (kpinterface->prefs->FetchOpt("SOUNDPREFIX") == "") kpinterface->prefs->SetOpt("SOUNDPREFIX", string(DATA_LOC) + "/kismet/wav", 1); sound_prefix = kpinterface->prefs->FetchOpt("SOUNDPREFIX"); vector sndpref = kpinterface->prefs->FetchOptVec("SOUND"); vector sndparse; string snd; int val; for (unsigned s = 0; s < sndpref.size(); s++) { sndparse = StrTokenize(sndpref[s], ","); if (sndparse.size() != 2) continue; snd = StrLower(sndparse[0]); // val = (StrLower(sndparse[1]) == "true"); val = StringToBool(sndparse[1], 0); if (snd == "newnet") snd_new = val; else if (snd == "packet") snd_packet = val; else if (snd == "gpslock") snd_gpslock = val; else if (snd == "gpslost") snd_gpslost = val; else if (snd == "alert") snd_alert = val; } if (snd_new < 0) { snd_new = 1; sndpref.push_back("newnet,true"); } if (snd_packet < 0) { snd_packet = 1; sndpref.push_back("packet,true"); } if (snd_gpslock < 0) { snd_gpslock = 1; sndpref.push_back("gpslock,true"); } if (snd_gpslost < 0) { snd_gpslost = 1; sndpref.push_back("gpslost,true"); } if (snd_alert == 0) { snd_alert = 1; sndpref.push_back("alert,true"); } kpinterface->prefs->SetOptVec("sound", sndpref, time(0)); sndpref = kpinterface->prefs->FetchOptVec("speech"); for (unsigned int x = 0; x < sndpref.size(); x++) { sndparse = QuoteStrTokenize(sndpref[x], ","); if (sndparse.size() != 2) continue; snd = StrLower(sndparse[0]); if (snd == "new") spk_new = sndparse[1]; else if (snd == "alert") spk_alert = sndparse[1]; else if (snd == "gpslost") spk_gpslost = sndparse[1]; else if (snd == "gpslock") spk_gpslock = sndparse[1]; } if (spk_new == "") { spk_new = "New network detected s.s.i.d. %1 channel %2"; sndpref.push_back("new,\"" + spk_new + "\""); } if (spk_alert == "") { spk_alert = "Alert %1"; sndpref.push_back("alert,\"" + spk_alert + "\""); } if (spk_gpslost == "") { spk_gpslost = "G.P.S. signal lost"; sndpref.push_back("gpslost,\"" + spk_gpslost + "\""); } if (spk_gpslock == "") { spk_gpslock = "G.P.S. signal O.K."; sndpref.push_back("gpslock,\"" + spk_gpslock + "\""); } kpinterface->prefs->SetOptVec("SPEECH", sndpref, 1); } void Kis_Main_Panel::SpeakString(string type, vector text) { string base; if (type == "new") base = spk_new; else if (type == "alert") base = spk_alert; else if (type == "gpslost") base = spk_gpslost; else if (type == "gpslock") base = spk_gpslock; else return; for (unsigned int x = 0; x < text.size(); x++) { string k = "%" + IntToString(x + 1); if (base.find(k) != string::npos) base.replace(base.find(k), k.length(), text[x]); } globalreg->soundctl->SayText(base); } void Kis_Main_Panel::Proto_INFO(CLIPROTO_CB_PARMS) { // "packets,llcpackets,rate,networks", if (proto_parsed->size() < 4) return; int pkts, datapkts, networks; if (sscanf((*proto_parsed)[0].word.c_str(), "%d", &pkts) != 1) return; if (sscanf((*proto_parsed)[1].word.c_str(), "%d", &datapkts) != 1) return; // Parse out of order, networks are a higher sound priority than packets if (sscanf((*proto_parsed)[3].word.c_str(), "%d", &networks) != 1) return; // Use the sound pref tracker as the # of new networks counter if (networks != 0 && snd_new != 0 && networks != snd_new) { snd_new = networks; globalreg->soundctl->PlaySound(sound_prefix + string("/") + "new.wav"); } if ((*proto_parsed)[2].word != "0" && snd_packet) globalreg->soundctl->PlaySound(sound_prefix + string("/") + "packet.wav"); if (lastpackets == 0) lastpackets = pkts; if (lastdata == 0) lastdata = datapkts; pps.push_back(pkts - lastpackets); datapps.push_back(datapkts - lastdata); if (pps.size() > 50) pps.erase(pps.begin(), pps.begin() + pps.size() - 50); if (datapps.size() > 50) datapps.erase(datapps.begin(), datapps.begin() + datapps.size() - 50); lastpackets = pkts; lastdata = datapkts; } void Kis_Main_Panel::Proto_GPS(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) agg_gps_num) return; int fnum = 0, connected, fix; float lat, lon, alt, spd; string gpstext; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &connected) != 1) return; if (connected <= 0) { gpsinfo->SetText("No GPS data (GPS not connected)"); return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &fix) != 1) return; if (fix < 2) { gpsinfo->SetText("No GPS info (GPS does not have signal)"); return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &lat) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &lon) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &alt) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &spd) != 1) return; // Use the gpslock/lost prefs to determine if we play the sound or if we // already have played this state if (fix < 2 && snd_gpslost != 0 && snd_gpslost < 2) { snd_gpslost = 2; if (snd_gpslock) snd_gpslock = 1; globalreg->soundctl->PlaySound(sound_prefix + string("/") + "gpslost.wav"); } if (fix >= 2 && snd_gpslock != 0 && snd_gpslock < 2) { snd_gpslock = 2; if (snd_gpslost) snd_gpslost = 1; globalreg->soundctl->PlaySound(sound_prefix + string("/") + "gpslock.wav"); } int eng = StrLower(kpinterface->prefs->FetchOpt("GPSUNIT")) != "metric"; gpstext = string("GPS ") + NtoString(lat, 6).Str() + string(" ") + NtoString(lon, 6).Str() + string(" "); // Convert to m/hr spd *= 3600; if (eng) { // Convert speed to feet/hr spd *= 3.2808; // Convert alt to feet alt *= 3.2808; } if (eng) { if (spd > 2500) gpstext += "Spd: " + NtoString(spd / 5280, 2).Str() + " mph "; else gpstext += "Spd: " + NtoString(spd, 2).Str() + " fph "; if (alt > 2500) gpstext += "Alt: " + NtoString(alt / 5280, 2).Str() + " m "; else gpstext += "Alt: " + NtoString(alt, 2).Str() + " ft "; } else { if (spd > 1000) gpstext += "Spd: " + NtoString(spd / 1000, 2).Str() + "Km/hr "; else gpstext += "Spd: " + NtoString(spd, 2).Str() + "m/hr "; if (alt > 1000) gpstext += "Alt: " + NtoString(alt / 1000, 2).Str() + "Km "; else gpstext += "Alt: " + NtoString(alt, 2).Str() + "m "; } gpsinfo->SetText(gpstext + IntToString(fix) + string("d fix")); } void Kis_Main_Panel::Proto_BATTERY(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < 4) return; // Bat-comment! string battxt; int charging = 0, percentage = 0, ac = 0, remaining = 0; if (sscanf((*proto_parsed)[0].word.c_str(), "%d", &percentage) == 0) return; if (sscanf((*proto_parsed)[1].word.c_str(), "%d", &charging) == 0) return; if (sscanf((*proto_parsed)[2].word.c_str(), "%d", &ac) == 0) return; if (sscanf((*proto_parsed)[3].word.c_str(), "%d", &remaining) == 0) return; battxt = "Pwr: "; if (ac) { battxt += "AC"; if (charging == 1) battxt += " (Charging)"; } else { battxt += "Battery " + IntToString(percentage) + "%"; } if (remaining > 0 && ac == 0) { remaining /= 60; battxt += " " + IntToString(remaining / 60) + "h " + NtoString(remaining % 60, 2, 0).Str() + "m"; } batteryinfo->SetText(battxt); } void Kis_Main_Panel::Proto_ALERT(CLIPROTO_CB_PARMS) { if (snd_alert) globalreg->soundctl->PlaySound(sound_prefix + string("/") + "alert.wav"); } void Kis_Main_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); menu->SetPosition(1, 0, 0, 0); // All we have to do is position the main box now vbox->SetPosition(1, 1, in_x - 1, in_y - 2); /* netlist->SetPosition(in_sx + 2, in_sy + 1, in_x - 15, in_y - 8); statustext->SetPosition(in_sx + 1, in_y - 7, in_x - 2, 5); */ } void Kis_Main_Panel::DrawPanel() { // Set up the source list vector sourceinfotxt; map *cardmap = kpinterface->FetchNetCardMap(); for (map::iterator x = cardmap->begin(); x != cardmap->end(); ++x) { sourceinfotxt.push_back("\004u" + x->second->name + "\004U"); if (x->second->dwell) sourceinfotxt.push_back("Dwell"); else if (x->second->hopping) sourceinfotxt.push_back("Hop"); else sourceinfotxt.push_back(IntToString(x->second->channel)); } sourceinfo->SetText(sourceinfotxt); UpdateSortMenu(); if (netlist->FetchSelectedNetgroup() != NULL) { menu->EnableMenuItem(mi_addnote); menu->EnableMenuItem(mi_netdetails); menu->EnableMenuItem(mi_clientlist); } else { menu->DisableMenuItem(mi_addnote); menu->DisableMenuItem(mi_netdetails); menu->DisableMenuItem(mi_clientlist); } Kis_Panel::DrawPanel(); } int Kis_Main_Panel::MouseEvent(MEVENT *mevent) { int con = kpinterface->FetchNetConnected(); if (con == 0 && connect_enable == 0) { menu->EnableMenuItem(mi_connect); menu->DisableMenuItem(mi_disconnect); connect_enable = 1; } else if (con && connect_enable) { menu->EnableMenuItem(mi_disconnect); menu->DisableMenuItem(mi_connect); connect_enable = 0; } if (kpinterface->FetchServerFramework() == NULL || (kpinterface->FetchServerFramework() != NULL && kpinterface->FetchServerFramework()->Valid() == 0)) { menu->EnableMenuItem(mi_startserver); } else { menu->DisableMenuItem(mi_startserver); } return Kis_Panel::MouseEvent(mevent); } int Kis_Main_Panel::KeyPress(int in_key) { int con = kpinterface->FetchNetConnected(); if (con == 0 && connect_enable == 0) { menu->EnableMenuItem(mi_connect); menu->DisableMenuItem(mi_disconnect); connect_enable = 1; } else if (con && connect_enable) { menu->EnableMenuItem(mi_disconnect); menu->DisableMenuItem(mi_connect); connect_enable = 0; } return Kis_Panel::KeyPress(in_key); } void Kis_Main_Panel::AddViewSeparator() { if (mn_view_appended) return; mn_view_appended = 1; menu->AddMenuItem("-", mn_view, 0); } void Kis_Main_Panel::AddSortSeparator() { if (mn_sort_appended) return; mn_sort_appended = 1; menu->AddMenuItem("-", mn_sort, 0); } // Dump text to stderr void kmp_textcli_stderr(TEXTCLI_PARMS) { fprintf(stderr, "[SERVER] %s\n", text.c_str()); } // Set fatal condition on error void kmp_spawnserver_fail(CLIFRAME_FAIL_CB_PARMS) { fprintf(stderr, "Spawned Kismet server has exited\n"); globalreg->fatal_condition = 1; } // This function is "fun". // // In any case, we're shutting down. // // If the user says "yes, kill the server", and we started the server locally, // we teardown the UI structure, set a callback that prints to stderr on the server, // and set a death callback that sets the system to fatal and turns us off entirely. // // Otherwise, we just set the server to teardown. extern void CatchShutdown(int); void kmp_prompt_killserver(KIS_PROMPT_CB_PARMS) { // Kis_Main_Panel *kmp = (Kis_Main_Panel *) auxptr; TextCliFrame *cf = globalreg->panel_interface->FetchServerFramework(); PopenClient *po = globalreg->panel_interface->FetchServerPopen(); KisNetClient *knc = globalreg->panel_interface->FetchNetClient(); endwin(); if (ok && cf != NULL && po != NULL) { // Kill and spin down cleanly cf->RegisterCallback(kmp_textcli_stderr, NULL); cf->RegisterFailCB(kmp_spawnserver_fail, NULL); po->SoftKillConnection(); } else if (ok && knc != NULL) { // Send a kill command if we're killing and we're not running it locally knc->InjectCommand("SHUTDOWN"); } else if (po != NULL) { // Detatch po->DetatchConnection(); } if (knc != NULL) knc->Shutdown(); // Spindown CatchShutdown(0); } void Kis_Main_Panel::MenuAction(int opt) { int con = kpinterface->FetchNetConnected(); // Menu processed an event, do something with it if (opt == mi_quit) { if (con == 0 && (kpinterface->FetchServerFramework() == NULL || (kpinterface->FetchServerFramework() != NULL && kpinterface->FetchServerFramework()->Valid() == 0))) { kmp_prompt_killserver(globalreg, 1, -1, NULL); } // if ((kpinterface->prefs->FetchOpt("STOP_PROMPTSERVER") == "true" || // kpinterface->prefs->FetchOpt("STOP_PROMPTSERVER") == "") && // (kpinterface->prefs->FetchOpt("STOP_SERVER") == "true" || // kpinterface->prefs->FetchOpt("STOP_SERVER") == "")) { if (kpinterface->prefs->FetchOptBoolean("STOP_PROMPTSERVER", 1) && kpinterface->prefs->FetchOptBoolean("STOP_SERVER", 1)) { vector t; t.push_back("Stop Kismet server before quitting?"); t.push_back("This will stop capture & shut down any other"); t.push_back("clients that might be connected to this server"); if (globalreg->panel_interface->FetchServerFramework() != NULL) { t.push_back("Not stopping the server will leave it running in"); t.push_back("the background."); } Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, kpinterface); kpp->SetTitle("Stop Kismet Server"); kpp->SetDisplayText(t); if (globalreg->panel_interface->FetchServerFramework() == NULL) { kpp->SetButtonText("Kill", "Leave"); } else { kpp->SetButtonText("Kill", "Background"); } kpp->SetCallback(kmp_prompt_killserver, this); kpp->SetDefaultButton(1); kpinterface->QueueModalPanel(kpp); return; // } else if (kpinterface->prefs->FetchOpt("STOP_SERVER") == "true" || // kpinterface->prefs->FetchOpt("STOP_SERVER") == "") { } else if (kpinterface->prefs->FetchOptBoolean("STOP_SERVER", 1)) { // if we're stopping the server without prompt, just call the // prompt handler and tell it OK kmp_prompt_killserver(globalreg, 1, -1, NULL); } else { // Otherwise we're not prompting and we're not just stopping, // so exit and don't stop kmp_prompt_killserver(globalreg, 0, -1, NULL); } return; } else if (opt == mi_connect) { Kis_Connect_Panel *cp = new Kis_Connect_Panel(globalreg, kpinterface); kpinterface->AddPanel(cp); } else if (opt == mi_startserver) { Kis_Spawn_Panel *sp = new Kis_Spawn_Panel(globalreg, kpinterface); kpinterface->AddPanel(sp); } else if (opt == mi_serverconsole) { Kis_Console_Panel *cp = new Kis_Console_Panel(globalreg, kpinterface); kpinterface->AddPanel(cp); } else if (opt == mi_disconnect) { if (con) { kpinterface->RemoveNetClient(); } } else if (opt == mi_sort_auto) { kpinterface->prefs->SetOpt("NETLIST_SORT", "auto", time(0)); } else if (opt == mi_sort_type) { kpinterface->prefs->SetOpt("NETLIST_SORT", "type", time(0)); } else if (opt == mi_sort_chan) { kpinterface->prefs->SetOpt("NETLIST_SORT", "channel", time(0)); } else if (opt == mi_sort_crypt) { kpinterface->prefs->SetOpt("NETLIST_SORT", "crypt_type", time(0)); } else if (opt == mi_sort_first) { kpinterface->prefs->SetOpt("NETLIST_SORT", "first", time(0)); } else if (opt == mi_sort_first_d) { kpinterface->prefs->SetOpt("NETLIST_SORT", "first_desc", time(0)); } else if (opt == mi_sort_last) { kpinterface->prefs->SetOpt("NETLIST_SORT", "last", time(0)); } else if (opt == mi_sort_last_d) { kpinterface->prefs->SetOpt("NETLIST_SORT", "last_desc", time(0)); } else if (opt == mi_sort_bssid) { kpinterface->prefs->SetOpt("NETLIST_SORT", "bssid", time(0)); } else if (opt == mi_sort_ssid) { kpinterface->prefs->SetOpt("NETLIST_SORT", "ssid", time(0)); } else if (opt == mi_sort_sdbm) { kpinterface->prefs->SetOpt("NETLIST_SORT", "signal", time(0)); } else if (opt == mi_sort_packets) { kpinterface->prefs->SetOpt("NETLIST_SORT", "packets", time(0)); } else if (opt == mi_sort_packets_d) { kpinterface->prefs->SetOpt("NETLIST_SORT", "packets_desc", time(0)); } else if (opt == mi_netdetails) { Kis_NetDetails_Panel *dp = new Kis_NetDetails_Panel(globalreg, kpinterface); kpinterface->AddPanel(dp); } else if (opt == mi_addnote) { Kis_AddNetNote_Panel *dp = new Kis_AddNetNote_Panel(globalreg, kpinterface); kpinterface->AddPanel(dp); } else if (opt == mi_clientlist) { Kis_Clientlist_Panel *cl = new Kis_Clientlist_Panel(globalreg, kpinterface); kpinterface->AddPanel(cl); } else if (opt == mi_chandetails) { Kis_ChanDetails_Panel *dp = new Kis_ChanDetails_Panel(globalreg, kpinterface); kpinterface->AddPanel(dp); } else if (opt == mi_gps) { Kis_Gps_Panel *gp = new Kis_Gps_Panel(globalreg, kpinterface); kpinterface->AddPanel(gp); } else if (opt == mi_alerts) { Kis_AlertDetails_Panel *ap = new Kis_AlertDetails_Panel(globalreg, kpinterface); kpinterface->AddPanel(ap); } else if (opt == mi_showsummary || opt == mi_showstatus || opt == mi_showpps || opt == mi_showgps || opt == mi_showbattery || opt == mi_showsources || opt == mi_shownetworks || opt == mi_showclients) { UpdateViewMenu(opt); } else if (opt == mi_addcard) { Kis_AddCard_Panel *acp = new Kis_AddCard_Panel(globalreg, kpinterface); kpinterface->AddPanel(acp); } else if (opt == mi_conf) { Kis_Chanconf_Panel *cp = new Kis_Chanconf_Panel(globalreg, kpinterface); kpinterface->AddPanel(cp); } else if (opt == mi_addplugin) { Kis_Plugin_Picker *pp = new Kis_Plugin_Picker(globalreg, kpinterface); kpinterface->AddPanel(pp); } else if (opt == mi_colorprefs) { SpawnColorPrefs(); } else if (opt == mi_startprefs) { Kis_StartupPref_Panel *sp = new Kis_StartupPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(sp); } else if (opt == mi_serverprefs) { SpawnServerPrefs(); } else if (opt == mi_netcolprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; bssid_column_details[x].pref != NULL; x++) { cpp->AddColumn(bssid_column_details[x].pref, bssid_column_details[x].name); } cpp->ColumnPref("netlist_columns", "Network List"); kpinterface->AddPanel(cpp); } else if (opt == mi_netextraprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; bssid_extras_details[x].pref != NULL; x++) { cpp->AddColumn(bssid_extras_details[x].pref, bssid_extras_details[x].name); } cpp->ColumnPref("netlist_extras", "Network Extras"); kpinterface->AddPanel(cpp); } else if (opt == mi_clicolprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; client_column_details[x].pref != NULL; x++) { cpp->AddColumn(client_column_details[x].pref, client_column_details[x].name); } cpp->ColumnPref("clientlist_columns", "Client List"); kpinterface->AddPanel(cpp); } else if (opt == mi_cliextraprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; client_extras_details[x].pref != NULL; x++) { cpp->AddColumn(client_extras_details[x].pref, client_extras_details[x].name); } cpp->ColumnPref("clientlist_extras", "Client Extras"); kpinterface->AddPanel(cpp); } else if (opt == mi_infoprefs) { SpawnInfoPrefs(); } else if (opt == mi_gpsprefs) { Kis_GpsPref_Panel *pp = new Kis_GpsPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(pp); } else if (opt == mi_audioprefs) { Kis_AudioPref_Panel *pp = new Kis_AudioPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(pp); } else if (opt == mi_warnprefs) { Kis_WarnPref_Panel *pp = new Kis_WarnPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(pp); } else { for (unsigned int p = 0; p < plugin_menu_vec.size(); p++) { if (opt == plugin_menu_vec[p].menuitem) { (*(plugin_menu_vec[p].callback))(plugin_menu_vec[p].auxptr); break; } } } } int Kis_Main_Panel::AddPluginMenuItem(string in_name, int (*callback)(void *), void *auxptr) { plugin_menu_opt mo; // Hide the "no plugins" menu and make our own item menu->SetMenuItemVis(mi_noplugins, 0); mo.menuitem = menu->AddMenuItem(in_name, mn_plugins, 0); mo.callback = callback; mo.auxptr = auxptr; plugin_menu_vec.push_back(mo); return mo.menuitem; } void Kis_Main_Panel::AddColorPref(string in_pref, string in_text) { colorpref cp; for (unsigned int x = 0; x < color_pref_vec.size(); x++) { if (color_pref_vec[x].pref == in_pref) return; } cp.pref = in_pref; cp.text = in_text; color_pref_vec.push_back(cp); } void Kis_Main_Panel::SpawnColorPrefs() { Kis_ColorPref_Panel *cpp = new Kis_ColorPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; x < color_pref_vec.size(); x++) { cpp->AddColorPref(color_pref_vec[x].pref, color_pref_vec[x].text); } kpinterface->AddPanel(cpp); } void Kis_Main_Panel::SpawnInfoPrefs() { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; info_bits_details[x][0] != NULL; x++) { cpp->AddColumn(info_bits_details[x][0], info_bits_details[x][1]); } cpp->ColumnPref("netinfo_items", "Info Pane"); kpinterface->AddPanel(cpp); } void Kis_Main_Panel::SpawnServerPrefs() { Kis_AutoConPref_Panel *cpp = new Kis_AutoConPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(cpp); } Kis_Display_NetGroup *Kis_Main_Panel::FetchSelectedNetgroup() { if (netlist == NULL) return NULL; return netlist->FetchSelectedNetgroup(); } vector *Kis_Main_Panel::FetchDisplayNetgroupVector() { if (netlist == NULL) return NULL; return netlist->FetchDisplayVector(); } void Kis_Main_Panel::UpdateSortMenu() { netsort_opts so = netlist->FetchSortMode(); menu->SetMenuItemChecked(mi_sort_auto, so == netsort_autofit); menu->SetMenuItemChecked(mi_sort_type, so == netsort_type); menu->SetMenuItemChecked(mi_sort_chan, so == netsort_channel); menu->SetMenuItemChecked(mi_sort_crypt, so == netsort_crypt); menu->SetMenuItemChecked(mi_sort_first, so == netsort_first); menu->SetMenuItemChecked(mi_sort_first_d, so == netsort_first_desc); menu->SetMenuItemChecked(mi_sort_last, so == netsort_last); menu->SetMenuItemChecked(mi_sort_last_d, so == netsort_last_desc); menu->SetMenuItemChecked(mi_sort_bssid, so == netsort_bssid); menu->SetMenuItemChecked(mi_sort_ssid, so == netsort_ssid); menu->SetMenuItemChecked(mi_sort_sdbm, so == netsort_sdbm); menu->SetMenuItemChecked(mi_sort_packets, so == netsort_packets); menu->SetMenuItemChecked(mi_sort_packets_d, so == netsort_packets_desc); } void Kis_Main_Panel::UpdateViewMenu(int mi) { string opt; if (mi == mi_showsummary) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSUMMARY"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWSUMMARY", "false", 1); menu->SetMenuItemChecked(mi_showsummary, 0); optbox->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWSUMMARY", "true", 1); menu->SetMenuItemChecked(mi_showsummary, 1); optbox->Show(); } } else if (mi == mi_showstatus) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSTATUS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWSTATUS", "false", 1); menu->SetMenuItemChecked(mi_showstatus, 0); statustext->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWSTATUS", "true", 1); menu->SetMenuItemChecked(mi_showstatus, 1); statustext->Show(); } } else if (mi == mi_showgps) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWGPS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWGPS", "false", 1); menu->SetMenuItemChecked(mi_showgps, 0); gpsinfo->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWGPS", "true", 1); menu->SetMenuItemChecked(mi_showgps, 1); gpsinfo->Show(); } } else if (mi == mi_showbattery) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWBAT"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWBAT", "false", 1); menu->SetMenuItemChecked(mi_showbattery, 0); batteryinfo->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWBAT", "true", 1); menu->SetMenuItemChecked(mi_showbattery, 1); batteryinfo->Show(); } } else if (mi == mi_showpps) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWPPS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWPPS", "false", 1); menu->SetMenuItemChecked(mi_showpps, 0); packetrate->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWPPS", "true", 1); menu->SetMenuItemChecked(mi_showpps, 1); packetrate->Show(); } } else if (mi == mi_showsources) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSOURCE"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWSOURCE", "false", 1); menu->SetMenuItemChecked(mi_showsources, 0); sourceinfo->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWSOURCE", "true", 1); menu->SetMenuItemChecked(mi_showsources, 1); sourceinfo->Show(); } } else if (mi == mi_shownetworks) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWNETLIST"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWNETLIST", "false", 1); menu->SetMenuItemChecked(mi_shownetworks, 0); netlist->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWNETLIST", "true", 1); menu->SetMenuItemChecked(mi_shownetworks, 1); netlist->Show(); } } else if (mi == mi_showclients) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWCLIENTLIST"); // if (opt == "true") { if (StringToBool(opt, 1)) { kpinterface->prefs->SetOpt("MAIN_SHOWCLIENTLIST", "false", 1); menu->SetMenuItemChecked(mi_showclients, 0); clientlist->Hide(); } else { kpinterface->prefs->SetOpt("MAIN_SHOWCLIENTLIST", "true", 1); menu->SetMenuItemChecked(mi_showclients, 1); clientlist->Show(); } } if (mi == -1) { opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSUMMARY"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showsummary, 1); optbox->Show(); } else { menu->SetMenuItemChecked(mi_showsummary, 0); optbox->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSTATUS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showstatus, 1); statustext->Show(); } else { menu->SetMenuItemChecked(mi_showstatus, 0); statustext->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWPPS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showpps, 1); packetrate->Show(); } else { menu->SetMenuItemChecked(mi_showpps, 0); packetrate->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWGPS"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showgps, 1); gpsinfo->Show(); } else { menu->SetMenuItemChecked(mi_showgps, 0); gpsinfo->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWBAT"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showbattery, 1); batteryinfo->Show(); } else { menu->SetMenuItemChecked(mi_showbattery, 0); batteryinfo->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWSOURCE"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showsources, 1); sourceinfo->Show(); } else { menu->SetMenuItemChecked(mi_showsources, 0); sourceinfo->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWNETLIST"); // if (opt == "" || opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_shownetworks, 1); netlist->Show(); } else { menu->SetMenuItemChecked(mi_shownetworks, 0); netlist->Hide(); } opt = kpinterface->prefs->FetchOpt("MAIN_SHOWCLIENTLIST"); // if (opt == "true") { if (StringToBool(opt, 1)) { menu->SetMenuItemChecked(mi_showclients, 1); clientlist->Show(); } else { menu->SetMenuItemChecked(mi_showclients, 0); clientlist->Hide(); } } } int ConnectButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Connect_Panel *) aux)->ButtonAction(component); return 1; } Kis_Connect_Panel::Kis_Connect_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { hostname = new Kis_Single_Input(globalreg, this); hostport = new Kis_Single_Input(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ConnectButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ConnectButtonCB, this); SetTitle("Connect to Server"); hostname->SetLabel("Host", LABEL_POS_LEFT); hostname->SetTextLen(120); hostname->SetCharFilter(FILTER_ALPHANUMSYM); hostname->SetText(kpinterface->prefs->FetchOpt("default_host"), -1, -1); hostport->SetLabel("Port", LABEL_POS_LEFT); hostport->SetTextLen(5); hostport->SetCharFilter(FILTER_NUM); hostport->SetText(kpinterface->prefs->FetchOpt("default_port"), -1, -1); okbutton->SetText("Connect"); cancelbutton->SetText("Cancel"); hostname->Show(); hostport->Show(); okbutton->Show(); cancelbutton->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(hostname, 0, 0); vbox->Pack_End(hostport, 0, 0); vbox->Pack_End(bbox, 1, 0); AddComponentVec(hostname, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(hostport, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); SetActiveComponent(hostname); Position(WIN_CENTER(8, 40)); } Kis_Connect_Panel::~Kis_Connect_Panel() { } void Kis_Connect_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); vbox->SetPosition(1, 2, in_x - 2, in_y - 3); } void Kis_Connect_Panel::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); DrawComponentVec(); wmove(win, 0, 0); } void Kis_Connect_Panel::ButtonAction(Kis_Panel_Component *component) { if (component == okbutton) { if (hostname->GetText() == "") { kpinterface->RaiseAlert("No hostname", "No hostname was provided for creating a\n" "new client connect to a Kismet server.\n" "A valid host name or IP is required.\n"); return; } if (hostport->GetText() == "") { kpinterface->RaiseAlert("No port", "No port number was provided for creating a\n" "new client connect to a Kismet server.\n" "A valid port number is required.\n"); return; } // Try to add a client string clitxt = "tcp://" + hostname->GetText() + ":" + hostport->GetText(); if (kpinterface->AddNetClient(clitxt, 1) < 0) kpinterface->RaiseAlert("Connect failed", "Failed to create new client connection\n" "to a Kismet server. Check the status\n" "pane for more information about what\n" "went wrong.\n"); globalreg->panel_interface->KillPanel(this); } else if (component == cancelbutton) { // Cancel and close globalreg->panel_interface->KillPanel(this); } } int PromptButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Prompt_Panel *) aux)->ButtonAction(component); return 1; } Kis_Prompt_Panel::Kis_Prompt_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { ftext = new Kis_Free_Text(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); check = new Kis_Checkbox(globalreg, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, PromptButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, PromptButtonCB, this); okbutton->SetText("OK"); cancelbutton->SetText("Cancel"); ftext->Show(); okbutton->Show(); cancelbutton->Show(); check->Hide(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(ftext, 1, 0); vbox->Pack_End(check, 0, 0); vbox->Pack_End(bbox, 0, 0); AddComponentVec(ftext, (KIS_PANEL_COMP_DRAW)); AddComponentVec(check, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); main_component = vbox; auxptr = NULL; callback = NULL; SetDefaultButton(1); } void Kis_Prompt_Panel::SetDefaultButton(int in_ok) { if (in_ok) { SetActiveComponent(okbutton); } else { SetActiveComponent(cancelbutton); } } void Kis_Prompt_Panel::SetButtonText(string in_oktext, string in_notext) { if (in_oktext == "") { okbutton->Hide(); cancelbutton->Show(); SetActiveComponent(cancelbutton); } else if (in_notext == "") { cancelbutton->Hide(); okbutton->Show(); SetActiveComponent(okbutton); } cancelbutton->SetText(in_notext); okbutton->SetText(in_oktext); } void Kis_Prompt_Panel::SetCheckText(string in_text) { int rp = 0; if (in_text == "" && check->GetVisible() != 0) { check->Hide(); rp = -1; } else if (in_text != "" && check->GetVisible() == 0) { check->Show(); rp = 1; } check->SetText(in_text); if (rp) Position(WIN_CENTER(sizey + rp, sizex)); } void Kis_Prompt_Panel::SetChecked(int in_check) { check->SetChecked(in_check); } void Kis_Prompt_Panel::SetCallback(ksp_prompt_cb in_callback, void *in_auxptr) { auxptr = in_auxptr; callback = in_callback; } void Kis_Prompt_Panel::SetDisplayText(vector in_text) { ftext->SetText(in_text); unsigned int maxlen = 0; for (unsigned int x = 0; x < in_text.size(); x++) if (in_text[x].length() > maxlen) maxlen = in_text[x].length(); Position(WIN_CENTER(in_text.size() + 3 + check->GetVisible(), maxlen + 4)); } Kis_Prompt_Panel::~Kis_Prompt_Panel() { delete bbox; } void Kis_Prompt_Panel::ButtonAction(Kis_Panel_Component *component) { if (component == okbutton) { if (callback != NULL) (*callback)(globalreg, 1, check->GetChecked(), auxptr); kpinterface->KillPanel(this); } else if (component == cancelbutton) { if (callback != NULL) (*callback)(globalreg, 0, check->GetChecked(), auxptr); kpinterface->KillPanel(this); } } int SpawnButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Spawn_Panel *) aux)->ButtonAction(component); return 1; } Kis_Spawn_Panel::Kis_Spawn_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { int log = 1; string logtitle, argpassed; // Wish we could use getopt here but can't figure out a way */ for (int x = 1; x < globalreg->argc; x++) { string vs = string(globalreg->argv[x]); if (vs == "-n" || vs == "--no-logging") { log = 0; } else if (vs == "-t" && x <= (globalreg->argc - 1)) { logtitle = string(globalreg->argv[x+1]); x++; } else { argpassed += vs + " "; } } spawn_console = 0; // if (kpinterface->prefs->FetchOpt("STARTUP_CONSOLE") == "true" || // kpinterface->prefs->FetchOpt("STARTUP_CONSOLE") == "") if (kpinterface->prefs->FetchOptBoolean("STARTUP_CONSOLE", 1)) spawn_console = 1; options = new Kis_Single_Input(globalreg, this); logname = new Kis_Single_Input(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); logging_check = new Kis_Checkbox(globalreg, this); console_check = new Kis_Checkbox(globalreg, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpawnButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpawnButtonCB, this); logging_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpawnButtonCB, this); console_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpawnButtonCB, this); SetTitle("Start Kismet Server"); options->SetLabel("Startup Options", LABEL_POS_LEFT); options->SetTextLen(120); options->SetCharFilter(FILTER_ALPHANUMSYM); if (globalreg->argc <= 1) { options->SetText(kpinterface->prefs->FetchOpt("default_server_options"), -1, -1); } else { options->SetText(argpassed, -1, -1); } logging_check->SetText("Logging"); logging_check->SetChecked(log); logname->SetLabel("Log Title", LABEL_POS_LEFT); logname->SetTextLen(64); logname->SetCharFilter(FILTER_ALPHA FILTER_NUM); if (logtitle == "") logname->SetText("Kismet", -1, -1); else logname->SetText(logtitle, -1, -1); console_check->SetText("Show Console"); console_check->SetChecked(spawn_console); okbutton->SetText("Start"); cancelbutton->SetText("Cancel"); options->Show(); okbutton->Show(); cancelbutton->Show(); logging_check->Show(); logname->Show(); console_check->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(options, 0, 0); vbox->Pack_End(logging_check, 0, 0); vbox->Pack_End(logname, 0, 0); vbox->Pack_End(console_check, 0, 0); vbox->Pack_End(bbox, 1, 0); AddComponentVec(options, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(logging_check, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(logname, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(console_check, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); main_component = vbox; SetActiveComponent(okbutton); Position(WIN_CENTER(11, 40)); } Kis_Spawn_Panel::~Kis_Spawn_Panel() { delete bbox; } void Kis_Spawn_Panel::ButtonAction(Kis_Panel_Component *component) { if (component == okbutton) { string opt = options->GetText(); if (logging_check->GetChecked()) { opt += " -t " + logname->GetText(); } else { opt += " -n"; } kpinterface->SpawnServer(opt); kpinterface->KillPanel(this); if (console_check->GetChecked()) { Kis_Console_Panel *cp = new Kis_Console_Panel(globalreg, kpinterface); kpinterface->AddPanel(cp); } } else if (component == cancelbutton) { // Cancel and close kpinterface->KillPanel(this); } } int ConsoleButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Console_Panel *) aux)->ButtonAction(component); return 1; } void ConsoleTextCB(TEXTCLI_PARMS) { ((Kis_Console_Panel *) auxptr)->AddConsoleText(text); } Kis_Console_Panel::Kis_Console_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { constext = new Kis_Free_Text(globalreg, this); killbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); killbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ConsoleButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ConsoleButtonCB, this); SetTitle("Kismet Server Console"); // Import the existing console constext->SetFollowTail(1); constext->SetMaxText(150); if (kpinterface->FetchServerFramework() == NULL) { constext->SetText("Kismet server not started (or not started via this client)"); textcb = -1; } else { constext->SetText(*(kpinterface->FetchServerConsole())); textcb = kpinterface->FetchServerFramework()->RegisterCallback(ConsoleTextCB, this); } okbutton->SetText("Close Console Window"); killbutton->SetText("Kill Server"); constext->Show(); okbutton->Show(); killbutton->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(killbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(constext, 1, 0); vbox->Pack_End(bbox, 0, 0); AddComponentVec(constext, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(killbutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); SetActiveComponent(constext); main_component = vbox; Position(WIN_CENTER(LINES, COLS)); } Kis_Console_Panel::~Kis_Console_Panel() { if (kpinterface->FetchServerFramework() != NULL) { kpinterface->FetchServerFramework()->RemoveCallback(textcb); } } void Kis_Console_Panel::ButtonAction(Kis_Panel_Component *component) { if (component == okbutton) { kpinterface->KillPanel(this); } if (component == killbutton) { kpinterface->KillServer(); } } void Kis_Console_Panel::AddConsoleText(string in_text) { constext->AppendText(in_text); } int AddCardButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AddCard_Panel *) aux)->ButtonAction(component); return 1; } Kis_AddCard_Panel::Kis_AddCard_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { srcopts = new Kis_Single_Input(globalreg, this); srciface = new Kis_Single_Input(globalreg, this); srcname = new Kis_Single_Input(globalreg, this); okbutton = new Kis_Button(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddCardButtonCB, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddCardButtonCB, this); AddComponentVec(srciface, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(srcname, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(srcopts, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("Add Source"); srciface->SetLabel("Intf", LABEL_POS_LEFT); srciface->SetTextLen(128); srciface->SetCharFilter(FILTER_ALPHANUMSYM); srciface->Show(); srcname->SetLabel("Name", LABEL_POS_LEFT); srcname->SetTextLen(32); srcname->SetCharFilter(FILTER_ALPHANUMSYM); srcname->Show(); srcopts->SetLabel("Opts", LABEL_POS_LEFT); srcopts->SetTextLen(128); srcopts->SetCharFilter(FILTER_ALPHANUMSYM); srcopts->Show(); okbutton->SetText("Add"); okbutton->Show(); cancelbutton->SetText("Cancel"); cancelbutton->Show(); target_cli = NULL; vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(srciface, 0, 0); vbox->Pack_End(srcname, 0, 0); vbox->Pack_End(srcopts, 0, 0); vbox->Pack_End(bbox, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); target_cli = kpinterface->FetchNetClient(); SetActiveComponent(srciface); main_component = vbox; Position(WIN_CENTER(10, 40)); } Kis_AddCard_Panel::~Kis_AddCard_Panel() { } void Kis_AddCard_Panel::DrawPanel() { if (kpinterface->FetchNetConnected() == 0) { kpinterface->RaiseAlert("Not connected", "Not connected to a Kismet server, sources can\n" "only be added once a connection has been made."); kpinterface->KillPanel(this); return; } ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); wattrset(win, text_color); DrawTitleBorder(); DrawComponentVec(); wmove(win, 0, 0); } void Kis_AddCard_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { string srcdef; if (srciface->GetText() == "") { kpinterface->RaiseAlert("No source interface", "No source interface was provided for\n" "creating a new source. A source\n" "interface is required.\n"); return; } srcdef = srciface->GetText() + ":"; if (srcname->GetText() != "") { srcdef += "name=" + srcname->GetText() + ","; } if (srcopts->GetText() != "") { srcdef += srcopts->GetText(); } if (target_cli == NULL) { globalreg->panel_interface->KillPanel(this); return; } if (target_cli->Valid() == 0) { kpinterface->RaiseAlert("Server unavailable", "The selected server is not available.\n"); return; } // Build a command and inject it string srccmd; srccmd = "ADDSOURCE " + srcdef; target_cli->InjectCommand(srccmd); globalreg->panel_interface->KillPanel(this); } else if (in_button == cancelbutton) { // Cancel and close globalreg->panel_interface->KillPanel(this); } return; } int PluginPickerButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Plugin_Picker *) aux)->ButtonAction(component); return 1; } void kpp_proto_PLUGIN_complete(CLICMD_CB_PARMS) { ((Kis_Plugin_Picker *) auxptr)->Proto_PLUGIN_complete(); } void kpp_proto_PLUGIN(CLIPROTO_CB_PARMS) { ((Kis_Plugin_Picker *) auxptr)->Proto_PLUGIN(globalreg, proto_string, proto_parsed, srccli, auxptr); } void kpp_netclinetconfigured(CLICONF_CB_PARMS) { // Register the plugin handler with an ENABLE complete to notify us when we've // finished getting our list of initial plugins if (kcli->RegisterProtoHandler("PLUGIN", "name,version,description", kpp_proto_PLUGIN, auxptr, kpp_proto_PLUGIN_complete) < 0) { _MSG("Could not register PLUGIN protocol with remote server, " "connection will be terminated.", MSGFLAG_ERROR); kcli->KillConnection(); } } void kpp_netcliadd(KPI_ADDCLI_CB_PARMS) { if (add) netcli->AddConfCallback(kpp_netclinetconfigured, 1, auxptr); } Kis_Plugin_Picker::Kis_Plugin_Picker(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { pluglist = new Kis_Scrollable_Table(globalreg, this); srv_plugin_info = 0; vector titles; Kis_Scrollable_Table::title_data t; t.width = 40; t.title = "Client Plugin"; t.alignment = 0; titles.push_back(t); t.width = 9; t.title = "Auto Load"; t.alignment = 0; titles.push_back(t); t.width = 7; t.title = "Loaded"; t.alignment = 0; titles.push_back(t); pluglist->AddTitles(titles); pluglist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, PluginPickerButtonCB, this); pluglist->Show(); pluglist->SetPreferredSize(0, 10); AddComponentVec(pluglist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); vector ht; helptext = new Kis_Free_Text(globalreg, this); helptext->Show(); ht.push_back("For more information about Kismet UI plugins see the README"); ht.push_back("Select a plugin and press enter to toggle loaded/unloaded"); ht.push_back("Kismet UI Plugins:"); helptext->SetText(ht); AddComponentVec(helptext, (KIS_PANEL_COMP_DRAW)); ht.clear(); shelptext = new Kis_Free_Text(globalreg, this); shelptext->Show(); ht.push_back(""); ht.push_back("Server plugins cannot currently be loaded/unloaded from the UI"); ht.push_back("Kismet Server Plugins:"); shelptext->SetText(ht); AddComponentVec(shelptext, (KIS_PANEL_COMP_DRAW)); spluglist = new Kis_Scrollable_Table(globalreg, this); titles.clear(); t.width = 20; t.title = "Server Plugin"; t.alignment = 0; titles.push_back(t); t.width = 9; t.title = "Version"; t.alignment = 0; titles.push_back(t); t.width = 0; t.title = "Description"; t.alignment = 0; titles.push_back(t); spluglist->AddTitles(titles); spluglist->Show(); AddComponentVec(spluglist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); spluglist->SetPreferredSize(0, 4); okbutton = new Kis_Button(globalreg, this); okbutton->SetText("Close"); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, PluginPickerButtonCB, this); okbutton->Show(); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->SetCenter(0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(helptext, 0, 0); vbox->Pack_End(pluglist, 1, 0); vbox->Pack_End(shelptext, 0, 0); vbox->Pack_End(spluglist, 1, 0); vbox->Pack_End(okbutton, 0, 0); vbox->Show(); plugins = kpinterface->FetchPluginVec(); vector td; if (kpinterface->FetchNetClient() == NULL) { td.push_back(""); td.push_back(""); td.push_back("No server connection"); spluglist->ReplaceRow(0, td); } else { td.push_back(""); td.push_back(""); td.push_back("Loading list of Server plugins..."); spluglist->ReplaceRow(0, td); } for (unsigned int x = 0; x < plugins->size(); x++) { vector prefs = kpinterface->prefs->FetchOptVec("plugin_autoload"); string en = ""; td.clear(); td.push_back((*plugins)[x]->objectname); td.push_back("no"); // Figure out if we're going to autoload it for (unsigned int p = 0; p < prefs.size(); p++) { if (prefs[p] == (*plugins)[x]->objectname) { td[1] = "yes"; break; } } if ((*plugins)[x]->dlfileptr == (void *) 0x0) td.push_back("no"); else td.push_back("yes"); pluglist->ReplaceRow(x, td); } if (plugins->size() == 0) { vector td; td.push_back("No plugins found"); td.push_back(""); td.push_back(""); pluglist->ReplaceRow(0, td); } SetActiveComponent(pluglist); main_component = vbox; SetTitle(""); net_plugin_ref = kpinterface->Add_NetCli_AddCli_CB(kpp_netcliadd, (void *) this); Position(WIN_CENTER(20, 70)); } Kis_Plugin_Picker::~Kis_Plugin_Picker() { kpinterface->Remove_Netcli_AddCli_CB(net_plugin_ref); kpinterface->Remove_All_Netcli_Conf_CB(kpp_netclinetconfigured); kpinterface->Remove_All_Netcli_ProtoHandler("PLUGIN", kpp_proto_PLUGIN, this); kpinterface->Remove_All_Netcli_Cmd_CB(kpp_proto_PLUGIN_complete, this); } void Kis_Plugin_Picker::Proto_PLUGIN(CLIPROTO_CB_PARMS) { // Bad kluge; plugin only sends on enable, but this is a bad assumption to // make. We'll make it anyway. if (proto_parsed->size() < 3) return; vector td; td.push_back((*proto_parsed)[0].word); td.push_back((*proto_parsed)[1].word); td.push_back((*proto_parsed)[2].word); spluglist->ReplaceRow(srv_plugin_info++, td); } void Kis_Plugin_Picker::Proto_PLUGIN_complete() { // Kick "no plugins" text on the server plugin table if we don't have // any, we only et here once ENABLE is done sending our initial *PLUGIN list if (srv_plugin_info == 0) { vector td; td.push_back(""); td.push_back(""); td.push_back("No plugins loaded"); } } void Kis_Plugin_Picker::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); DrawComponentVec(); wmove(win, 0, 0); } void Kis_Plugin_Picker::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { vector ldata; vector autoload; for (unsigned int x = 0; x < plugins->size(); x++) { ldata = pluglist->GetRow(x); if (ldata.size() < 3) continue; if (ldata[1] == "yes" && (*plugins)[x]->dlfileptr == 0x0) { kpinterface->LoadPlugin((*plugins)[x]->filename, (*plugins)[x]->objectname); autoload.push_back((*plugins)[x]->objectname); } } kpinterface->prefs->SetOptVec("plugin_autoload", autoload, 1); globalreg->panel_interface->KillPanel(this); return; } else if (in_button == pluglist) { int listkey = pluglist->GetSelected(); if (listkey >= 0 && listkey < (int) plugins->size()) { vector listdata = pluglist->GetSelectedData(); if (listdata[1] == "yes") { listdata[1] = "no"; if (listdata[2] != "yes") listdata[2] = "no"; } else { listdata[1] = "yes"; if (listdata[2] != "yes") listdata[2] = "Pending"; } pluglist->ReplaceRow(listkey, listdata); } } } int ChanconfButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Chanconf_Panel *) aux)->ButtonAction(component); return 1; } Kis_Chanconf_Panel::Kis_Chanconf_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { cardlist = new Kis_Scrollable_Table(globalreg, this); cardlist->SetHighlightSelected(1); cardlist->SetLockScrollTop(1); cardlist->SetDrawTitles(1); vector titles; Kis_Scrollable_Table::title_data t; t.width = 16; t.title = "Name"; t.alignment = 0; titles.push_back(t); t.width = 4; t.title = "Chan"; t.alignment = 2; titles.push_back(t); cardlist->AddTitles(titles); vector td; td.push_back("No sources found"); td.push_back("---"); cardlist->AddRow(0, td); cardlist->Show(); AddComponentVec(cardlist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); lockrad = new Kis_Radiobutton(globalreg, this); lockrad->SetText("Lock"); lockrad->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanconfButtonCB, this); lockrad->Show(); lockrad->SetChecked(1); AddComponentVec(lockrad, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); hoprad = new Kis_Radiobutton(globalreg, this); hoprad->SetText("Hop"); hoprad->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanconfButtonCB, this); hoprad->Show(); AddComponentVec(hoprad, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); dwellrad = new Kis_Radiobutton(globalreg, this); dwellrad->SetText("Dwell"); dwellrad->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanconfButtonCB, this); dwellrad->Show(); AddComponentVec(dwellrad, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); lockrad->LinkRadiobutton(hoprad); lockrad->LinkRadiobutton(dwellrad); dwellrad->LinkRadiobutton(hoprad); dwellrad->LinkRadiobutton(lockrad); hoprad->LinkRadiobutton(dwellrad); hoprad->LinkRadiobutton(lockrad); inpchannel = new Kis_Single_Input(globalreg, this); inpchannel->SetLabel("Chan/Freq", LABEL_POS_LEFT); inpchannel->SetTextLen(4); inpchannel->SetCharFilter(FILTER_NUM); inpchannel->Show(); AddComponentVec(inpchannel, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); inprate = new Kis_Single_Input(globalreg, this); inprate->SetLabel("Rate", LABEL_POS_LEFT); inprate->SetTextLen(4); inprate->SetCharFilter(FILTER_NUM); inprate->Hide(); AddComponentVec(inprate, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton = new Kis_Button(globalreg, this); okbutton->SetText("Change"); okbutton->Show(); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetText("Cancel"); cancelbutton->Show(); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanconfButtonCB, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanconfButtonCB, this); SetTitle("Configure Channel"); cbox = new Kis_Panel_Packbox(globalreg, this); cbox->SetPackH(); cbox->SetHomogenous(1); cbox->SetSpacing(1); cbox->SetCenter(1); AddComponentVec(cbox, KIS_PANEL_COMP_DRAW); cbox->Pack_End(lockrad, 0, 0); cbox->Pack_End(hoprad, 0, 0); cbox->Pack_End(dwellrad, 0, 0); cbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(0); bbox->SetCenter(1); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); bbox->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(cardlist, 1, 0); vbox->Pack_End(cbox, 0, 0); vbox->Pack_End(inpchannel, 0, 0); vbox->Pack_End(inprate, 0, 0); vbox->Pack_End(bbox, 0, 0); vbox->Show(); SetActiveComponent(cardlist); last_selected = 0; radio_changed = 0; last_radio = lockrad; main_component = vbox; Position(WIN_CENTER(14, 50)); } Kis_Chanconf_Panel::~Kis_Chanconf_Panel() { } void Kis_Chanconf_Panel::DrawPanel() { if (kpinterface->FetchNetConnected() == 0) { kpinterface->RaiseAlert("Not connected", "Not connected to a Kismet server, channels can\n" "only be configured once a connection has been made."); kpinterface->KillPanel(this); return; } map *cardmap = kpinterface->FetchNetCardMap(); vector td; for (map::iterator x = cardmap->begin(); x != cardmap->end(); ++x) { // Did we have a "no cards" row? int sel = cardlist->DelRow(0); td.clear(); td.push_back(x->second->name); if (x->second->hopping) td.push_back("Hop"); else td.push_back(IntToString(x->second->channel)); cardlist->ReplaceRow(x->second->uuid_hash, td); // If we had a no cards row, we need to select the first row we add if (sel == 1) { cardlist->SetSelected(x->second->uuid_hash); } } if (cardlist->GetSelected() != last_selected || radio_changed != 0) { KisPanelInterface::knc_card *card = NULL; for (map::iterator x = cardmap->begin(); x != cardmap->end(); ++x) { if (x->second->uuid_hash == (unsigned int) cardlist->GetSelected()) { card = x->second; break; } } // This should never happen but lets be safe if (card == NULL) { Kis_Panel::DrawPanel(); return; } // Set up the window for new cards OR set up the window based on the // new radiobutton selection if (last_selected != cardlist->GetSelected()) { if (card->hopping == 0 && card->dwell == 0) { lockrad->SetChecked(1); last_radio = lockrad; inpchannel->SetLabel("Chan/Freq", LABEL_POS_LEFT); inpchannel->SetTextLen(4); inpchannel->SetCharFilter(FILTER_NUM); inpchannel->SetText(IntToString(card->channel), -1, -1); inpchannel->Show(); inprate->Hide(); } else if (card->dwell != 0) { dwellrad->SetChecked(1); last_radio = dwellrad; inpchannel->SetLabel("Channels", LABEL_POS_LEFT); inpchannel->SetTextLen(256); inpchannel->SetCharFilter(string(FILTER_NUM) + "range-,:"); inpchannel->SetText(card->channellist, -1, -1); inpchannel->Show(); inprate->SetLabel("Dwell", LABEL_POS_LEFT); inprate->SetTextLen(3); inprate->SetCharFilter(FILTER_NUM); inprate->SetText(IntToString(card->dwell), -1, -1); inprate->Show(); } else if (card->hopping) { hoprad->SetChecked(1); last_radio = hoprad; inpchannel->SetLabel("Channels", LABEL_POS_LEFT); inpchannel->SetTextLen(256); inpchannel->SetCharFilter(string(FILTER_NUM) + "range-,:"); inpchannel->SetText(card->channellist, -1, -1); inpchannel->Show(); inprate->SetLabel("Rate", LABEL_POS_LEFT); inprate->SetTextLen(3); inprate->SetCharFilter(FILTER_NUM); inprate->SetText(IntToString(card->hopvelocity), -1, -1); inprate->Show(); } } else { if (last_radio == lockrad) { inpchannel->SetLabel("Chan/Freq", LABEL_POS_LEFT); inpchannel->SetTextLen(4); inpchannel->SetCharFilter(FILTER_NUM); inpchannel->SetText(IntToString(card->channel), -1, -1); inpchannel->Show(); // attack of the api doom, set the selected network channel as the // default lock channel if we're not already locked if (card->hopping == 0 && card->dwell == 0) { inpchannel->SetText(IntToString(card->channel), -1, -1); } else { if (kpinterface->FetchMainPanel()->FetchDisplayNetlist()->FetchSelectedNetgroup() != NULL) inpchannel->SetText(IntToString(kpinterface->FetchMainPanel()->FetchDisplayNetlist()->FetchSelectedNetgroup()->FetchNetwork()->channel), -1, -1); else inpchannel->SetText("6", -1, -1); } inprate->Hide(); } else if (last_radio == dwellrad) { inpchannel->SetLabel("Channels", LABEL_POS_LEFT); inpchannel->SetTextLen(256); inpchannel->SetCharFilter(string(FILTER_NUM) + ",:"); inpchannel->SetText(card->channellist, -1, -1); inpchannel->Show(); inprate->SetLabel("Dwell", LABEL_POS_LEFT); inprate->SetTextLen(3); inprate->SetCharFilter(FILTER_NUM); inprate->SetText(IntToString(card->dwell), -1, -1); inprate->Show(); } else if (last_radio == hoprad) { inpchannel->SetLabel("Channels", LABEL_POS_LEFT); inpchannel->SetTextLen(256); inpchannel->SetCharFilter(string(FILTER_NUM) + ",:"); inpchannel->SetText(card->channellist, -1, -1); inpchannel->Show(); inprate->SetLabel("Rate", LABEL_POS_LEFT); inprate->SetTextLen(3); inprate->SetCharFilter(FILTER_NUM); inprate->SetText(IntToString(card->hopvelocity), -1, -1); inprate->Show(); } } last_selected = cardlist->GetSelected(); radio_changed = 0; } Kis_Panel::DrawPanel(); } void Kis_Chanconf_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { uint32_t cardid = cardlist->GetSelected(); map *cardmap = kpinterface->FetchNetCardMap(); if (cardmap->size() == 0) { kpinterface->RaiseAlert("No cards", "No cards found in the list from the \n" "server, something is wrong.\n"); kpinterface->KillPanel(this); return; } if (cardid == 0) { kpinterface->RaiseAlert("No card", "No card selected\n"); return; } if (kpinterface->FetchNetConnected() == 0) { kpinterface->RaiseAlert("No server", "Not connected to a server, you \n" "shouldn't have been able to get to\n" "this point\n"); kpinterface->KillPanel(this); return; } KisPanelInterface::knc_card *card = NULL; for (map::iterator x = cardmap->begin(); x != cardmap->end(); ++x) { if (x->second->uuid_hash == cardid) { card = x->second; break; } } if (card == NULL) { kpinterface->RaiseAlert("No card", "No card matched the selected item\n" "this shouldn't happen.\n"); kpinterface->KillPanel(this); return; } if (last_radio == lockrad) { if (inpchannel->GetText() == "") { kpinterface->RaiseAlert("No channel", "No channel given\n"); return; } kpinterface->FetchNetClient()->InjectCommand("HOPSOURCE " + card->carduuid.UUID2String() + " LOCK " + inpchannel->GetText()); kpinterface->KillPanel(this); return; } else if (last_radio == hoprad || last_radio == dwellrad) { if (inpchannel->GetText() == "") { kpinterface->RaiseAlert("No channels", "No channels given\n"); return; } if (inprate->GetText() == "") { kpinterface->RaiseAlert("No rate", "No hop rate given\n"); return; } if (inpchannel->GetText() != card->channellist) kpinterface->FetchNetClient()->InjectCommand("CHANSOURCE " + card->carduuid.UUID2String() + " " + inpchannel->GetText()); kpinterface->FetchNetClient()->InjectCommand("HOPSOURCE " + card->carduuid.UUID2String() + string(" ") + string(last_radio == hoprad ? "HOP" : "DWELL") + string(" ") + inprate->GetText()); kpinterface->KillPanel(this); return; } } else if (in_button == cancelbutton) { globalreg->panel_interface->KillPanel(this); return; } else if (in_button == lockrad && last_radio != lockrad) { last_radio = lockrad; radio_changed = 1; } else if (in_button == hoprad && last_radio != hoprad) { last_radio = hoprad; radio_changed = 1; } else if (in_button == dwellrad && last_radio != dwellrad) { last_radio = dwellrad; radio_changed = 1; } } static const char *gpsinfo_fields[] = { "connected", "fix", "lat", "lon", "alt", "spd", "satinfo", NULL }; void GpsProtoGPS(CLIPROTO_CB_PARMS) { ((Kis_Gps_Panel *) auxptr)->Proto_GPS(globalreg, proto_string, proto_parsed, srccli, auxptr); } void GpsCliConfigured(CLICONF_CB_PARMS) { if (recon) return; string agg_gps_fields; TokenNullJoin(&agg_gps_fields, gpsinfo_fields); if (kcli->RegisterProtoHandler("GPS", agg_gps_fields, GpsProtoGPS, auxptr) < 0) { _MSG("Could not register GPS protocol with remote server, connection " "will be terminated", MSGFLAG_ERROR); kcli->KillConnection(); } } void GpsCliAdd(KPI_ADDCLI_CB_PARMS) { if (add == 0) return; netcli->AddConfCallback(GpsCliConfigured, 1, auxptr); } int GpsButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Gps_Panel *) aux)->ButtonAction(component); return 1; } Kis_Gps_Panel::Kis_Gps_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { okbutton = new Kis_Button(globalreg, this); okbutton->SetText("OK"); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsButtonCB, this); okbutton->Show(); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("GPS Info"); gpssiggraph = new Kis_IntGraph(globalreg, this); gpssiggraph->SetName("GPS_SIG"); gpssiggraph->SetPreferredSize(0, 12); gpssiggraph->SetInterpolation(0); gpssiggraph->SetMode(0); gpssiggraph->SetDrawScale(0); gpssiggraph->SetDrawLayers(0); gpssiggraph->AddExtDataVec("PRN SNR", 3, "gps_prn", "green,green", ' ', ' ', 1, &sat_info_vec); gpssiggraph->SetXLabels(sat_label_vec, "PRN SNR"); gpssiggraph->Show(); gpslocinfo = new Kis_Free_Text(globalreg, this); gpslocinfo->SetText("No GPS data (GPS not connected)"); gpslocinfo->Show(); gpsmoveinfo = new Kis_Free_Text(globalreg, this); gpsmoveinfo->Show(); gpssatinfo = new Kis_Free_Text(globalreg, this); gpssatinfo->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(gpslocinfo, 0, 0); vbox->Pack_End(gpsmoveinfo, 0, 0); vbox->Pack_End(gpssatinfo, 0, 0); vbox->Pack_End(gpssiggraph, 1, 0); vbox->Pack_End(okbutton, 0, 0); vbox->Show(); SetActiveComponent(okbutton); addref = kpinterface->Add_NetCli_AddCli_CB(GpsCliAdd, (void *) this); agg_gps_num = TokenNullJoin(&agg_gps_fields, gpsinfo_fields); main_component = vbox; Position(WIN_CENTER(20, 60)); } Kis_Gps_Panel::~Kis_Gps_Panel() { kpinterface->Remove_Netcli_AddCli_CB(addref); kpinterface->Remove_All_Netcli_Conf_CB(GpsCliConfigured); kpinterface->Remove_All_Netcli_ProtoHandler("GPS", GpsProtoGPS, this); } void Kis_Gps_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { kpinterface->KillPanel(this); return; } } #define DEG_2_RAD 0.0174532925199432957692369076848861271 void Kis_Gps_Panel::Proto_GPS(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) agg_gps_num) return; int fnum = 0, fix, connected; float lat, lon, alt, spd; string gpstext; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &connected) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &fix) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &lat) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &lon) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &alt) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &spd) != 1) return; int eng = StrLower(kpinterface->prefs->FetchOpt("GPSUNIT")) != "metric"; // Convert speed to m/hr spd *= 3600; if (eng) { // Convert speed to feet/hr spd *= 3.2808; // Convert alt to feet alt *= 3.2808; } if (connected == 0) { gpslocinfo->SetText("No GPS data (GPS not connected)"); gpsmoveinfo->SetText(""); return; } if (fix < 2) { gpslocinfo->SetText("No position (GPS does not have signal)"); gpsmoveinfo->SetText(""); } else { gpstext = string("Lat ") + NtoString(lat, 6).Str() + string(" Lon ") + NtoString(lon, 6).Str(); gpslocinfo->SetText(gpstext); if (eng) { // Reset gpstext for locinfo if (spd > 2500) gpstext = "Spd: " + NtoString(spd / 5280, 2).Str() + " mph "; else gpstext = "Spd: " + NtoString(spd, 2).Str() + " fph "; if (alt > 2500) gpstext += "Alt: " + NtoString(alt / 5280, 2).Str() + " m "; else gpstext += "Alt: " + NtoString(alt, 2).Str() + " ft "; } else { // Reset gpstext for locinfo if (spd > 1000) gpstext = "Spd: " + NtoString(spd / 1000, 2).Str() + "Km/hr "; else gpstext = "Spd: " + NtoString(spd, 2).Str() + "m/hr "; if (alt > 1000) gpstext += "Alt: " + NtoString(alt / 1000, 2).Str() + "Km "; else gpstext += "Alt: " + NtoString(alt, 2).Str() + "m "; } gpsmoveinfo->SetText(gpstext); } vector satblocks = StrTokenize((*proto_parsed)[fnum++].word, ","); sat_info_vec.clear(); sat_label_vec.clear(); // gpspolgraph->ClearPoints(); for (unsigned int x = 0; x < satblocks.size(); x++) { int prn, azimuth, elevation, snr; if (sscanf(satblocks[x].c_str(), "%d:%d:%d:%d", &prn, &elevation, &azimuth, &snr) != 4) continue; sat_info_vec.push_back(snr); Kis_IntGraph::graph_label lab; lab.position = x; lab.label = IntToString(prn); sat_label_vec.push_back(lab); /* Kis_PolarGraph::graph_point gp; gp.colorpref = "GPS_WEAKSNR"; gp.colordefault = "red,black"; gp.name = IntToString(prn); gp.r = ((90.0 - (double) elevation) / 90.0); gp.theta = azimuth * DEG_2_RAD; // fprintf(stderr, "debug - added %d %f %f\n", prn, gp.theta, gp.r); gpspolgraph->AddPoint(x, gp); */ } gpssatinfo->SetText(IntToString(sat_info_vec.size()) + " satellites" + (fix >= 2 ? string(", ") + IntToString(fix) + string("d fix") : ", No position")); gpssiggraph->SetXLabels(sat_label_vec, "PRN SNR"); } int ClientListButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Clientlist_Panel *) aux)->ButtonAction(component); return 1; } int ClientListMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_Clientlist_Panel *) aux)->MenuAction(status); return 1; } Kis_Clientlist_Panel::Kis_Clientlist_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf) : Kis_Panel(in_globalreg, in_kpf) { menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ClientListMenuCB, this); mn_clients = menu->AddMenu("Clients", 0); mi_nextnet = menu->AddMenuItem("Next network", mn_clients, 'n'); mi_prevnet = menu->AddMenuItem("Prev network", mn_clients, 'p'); menu->AddMenuItem("-", mn_clients, 0); mn_preferences = menu->AddSubMenuItem("Preferences", mn_clients, 'P'); mi_clicolprefs = menu->AddMenuItem("Client Columns...", mn_preferences, 'N'); mi_cliextraprefs = menu->AddMenuItem("Client Extras...", mn_preferences, 'E'); menu->AddMenuItem("-", mn_clients, 0); mi_close = menu->AddMenuItem("Close window", mn_clients, 'w'); mn_sort = menu->AddMenu("Sort", 0); mi_sort_auto = menu->AddMenuItem("Auto-fit", mn_sort, 'a'); menu->SetMenuItemCheckSymbol(mi_sort_auto, '*'); menu->AddMenuItem("-", mn_sort, 0); mi_sort_type = menu->AddMenuItem("Client Type", mn_sort, 't'); menu->SetMenuItemCheckSymbol(mi_sort_type, '*'); mi_sort_first = menu->AddMenuItem("First Seen", mn_sort, 'f'); menu->SetMenuItemCheckSymbol(mi_sort_first, '*'); mi_sort_first_d = menu->AddMenuItem("First Seen (descending)", mn_sort, 'F'); menu->SetMenuItemCheckSymbol(mi_sort_first_d, '*'); mi_sort_last = menu->AddMenuItem("Latest Seen", mn_sort, 'l'); menu->SetMenuItemCheckSymbol(mi_sort_last, '*'); mi_sort_last_d = menu->AddMenuItem("Latest Seen (descending)", mn_sort, 'L'); menu->SetMenuItemCheckSymbol(mi_sort_last_d, '*'); mi_sort_sdbm = menu->AddMenuItem("Signal", mn_sort, 'S'); menu->SetMenuItemCheckSymbol(mi_sort_sdbm, '*'); mi_sort_mac = menu->AddMenuItem("MAC", mn_sort, 's'); menu->SetMenuItemCheckSymbol(mi_sort_mac, '*'); mi_sort_packets = menu->AddMenuItem("Packets", mn_sort, 'p'); menu->SetMenuItemCheckSymbol(mi_sort_packets, '*'); mi_sort_packets_d = menu->AddMenuItem("Packets (descending)", mn_sort, 'P'); menu->SetMenuItemCheckSymbol(mi_sort_packets_d, '*'); mn_view = menu->AddMenu("Windows", 0); mi_addnote = menu->AddMenuItem("Add Note...", mn_view, 'N'); mi_details = menu->AddMenuItem("Client details...", mn_view, 'c'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); clientlist = new Kis_Clientlist(globalreg, this); clientlist->Show(); AddComponentVec(clientlist, KIS_PANEL_COMP_EVT); clientlist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ClientListButtonCB, this); nettitle = new Kis_Free_Text(globalreg, this); Kis_Display_NetGroup *cdng = NULL; Netracker::tracked_network *cnet = NULL; if ((cdng = clientlist->FetchSelectedNetgroup()) != NULL) { cnet = cdng->FetchNetwork(); if (cnet != NULL) { string ttext = "Selected network: "; ttext += cnet->bssid.Mac2String() + " "; if (cnet->lastssid != NULL) { ttext += string("(") + cnet->lastssid->ssid + string(")"); } nettitle->SetText(ttext); } } else { nettitle->SetText("No network selected"); } nettitle->Show(); AddComponentVec(nettitle, KIS_PANEL_COMP_DRAW); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(nettitle, 0, 0); vbox->Pack_End(clientlist, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); main_component = vbox; grapheventid = -1; UpdateSortMenu(); SetActiveComponent(clientlist); Position(WIN_CENTER(LINES, COLS)); } Kis_Clientlist_Panel::~Kis_Clientlist_Panel() { if (grapheventid >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(grapheventid); } void Kis_Clientlist_Panel::DrawPanel() { if (clientlist->FetchSelectedClient() != NULL) { menu->EnableMenuItem(mi_addnote); menu->EnableMenuItem(mi_details); } else { menu->DisableMenuItem(mi_addnote); menu->DisableMenuItem(mi_details); } Kis_Panel::DrawPanel(); } void Kis_Clientlist_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == clientlist && clientlist->FetchSelectedClient() != NULL) { Kis_ClientDetails_Panel *cp = new Kis_ClientDetails_Panel(globalreg, kpinterface); cp->SetClientlist(clientlist); kpinterface->AddPanel(cp); } return; } void Kis_Clientlist_Panel::MenuAction(int opt) { if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } else if (opt == mi_nextnet) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_DOWN); clientlist->UpdateDNG(); Kis_Display_NetGroup *cdng = NULL; Netracker::tracked_network *cnet = NULL; if ((cdng = clientlist->FetchSelectedNetgroup()) != NULL) { cnet = cdng->FetchNetwork(); if (cnet != NULL) { string ttext = "Selected network: "; ttext += cnet->bssid.Mac2String() + " "; if (cnet->lastssid != NULL) { ttext += string("(") + cnet->lastssid->ssid + string(")"); } nettitle->SetText(ttext); } } else { nettitle->SetText("No network selected"); } return; } else if (opt == mi_prevnet) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_UP); clientlist->UpdateDNG(); Kis_Display_NetGroup *cdng = NULL; Netracker::tracked_network *cnet = NULL; if ((cdng = clientlist->FetchSelectedNetgroup()) != NULL) { cnet = cdng->FetchNetwork(); if (cnet != NULL) { string ttext = "Selected network: "; ttext += cnet->bssid.Mac2String() + " "; if (cnet->lastssid != NULL) { ttext += string("(") + cnet->lastssid->ssid + string(")"); } nettitle->SetText(ttext); } } else { nettitle->SetText("No network selected"); } return; } else if (opt == mi_clicolprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; client_column_details[x].pref != NULL; x++) { cpp->AddColumn(client_column_details[x].pref, client_column_details[x].name); } cpp->ColumnPref("clientlist_columns", "Client List"); kpinterface->AddPanel(cpp); } else if (opt == mi_cliextraprefs) { Kis_ColumnPref_Panel *cpp = new Kis_ColumnPref_Panel(globalreg, kpinterface); for (unsigned int x = 0; client_extras_details[x].pref != NULL; x++) { cpp->AddColumn(client_extras_details[x].pref, client_extras_details[x].name); } cpp->ColumnPref("clientlist_extras", "Client Extras"); kpinterface->AddPanel(cpp); } else if (opt == mi_addnote) { Kis_AddCliNote_Panel *dp = new Kis_AddCliNote_Panel(globalreg, kpinterface); dp->SetClient(clientlist->FetchSelectedClient()); kpinterface->AddPanel(dp); } else if (opt == mi_details) { Kis_ClientDetails_Panel *cp = new Kis_ClientDetails_Panel(globalreg, kpinterface); cp->SetClientlist(clientlist); kpinterface->AddPanel(cp); return; } else if (opt == mi_sort_auto) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "auto", time(0)); } else if (opt == mi_sort_type) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "type", time(0)); } else if (opt == mi_sort_first) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "first", time(0)); } else if (opt == mi_sort_first_d) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "first_desc", time(0)); } else if (opt == mi_sort_last) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "last", time(0)); } else if (opt == mi_sort_last_d) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "last_desc", time(0)); } else if (opt == mi_sort_mac) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "mac", time(0)); } else if (opt == mi_sort_packets) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "packets", time(0)); } else if (opt == mi_sort_packets_d) { kpinterface->prefs->SetOpt("CLIENTLIST_SORT", "packets_desc", time(0)); } clientlist->UpdateSortPrefs(); UpdateSortMenu(); } void Kis_Clientlist_Panel::UpdateSortMenu() { clientsort_opts so = clientlist->FetchSortMode(); if (so == clientsort_autofit) menu->SetMenuItemChecked(mi_sort_auto, 1); else menu->SetMenuItemChecked(mi_sort_auto, 0); if (so == clientsort_type) menu->SetMenuItemChecked(mi_sort_type, 1); else menu->SetMenuItemChecked(mi_sort_type, 0); if (so == clientsort_first) menu->SetMenuItemChecked(mi_sort_first, 1); else menu->SetMenuItemChecked(mi_sort_first, 0); if (so == clientsort_first_desc) menu->SetMenuItemChecked(mi_sort_first_d, 1); else menu->SetMenuItemChecked(mi_sort_first_d, 0); if (so == clientsort_last) menu->SetMenuItemChecked(mi_sort_last, 1); else menu->SetMenuItemChecked(mi_sort_last, 0); if (so == clientsort_last_desc) menu->SetMenuItemChecked(mi_sort_last_d, 1); else menu->SetMenuItemChecked(mi_sort_last_d, 0); if (so == clientsort_mac) menu->SetMenuItemChecked(mi_sort_mac, 1); else menu->SetMenuItemChecked(mi_sort_mac, 0); if (so == clientsort_packets) menu->SetMenuItemChecked(mi_sort_packets, 1); else menu->SetMenuItemChecked(mi_sort_packets, 0); if (so == clientsort_packets_desc) menu->SetMenuItemChecked(mi_sort_packets_d, 1); else menu->SetMenuItemChecked(mi_sort_packets_d, 0); } void Kis_Clientlist_Panel::UpdateViewMenu(int mi) { return; } int Kis_Clientlist_Panel::GraphTimer() { return 0; } int AddNetNoteCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AddNetNote_Panel *) aux)->Action(component, status); return 1; } Kis_AddNetNote_Panel::Kis_AddNetNote_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { dng = NULL; notetxt = new Kis_Single_Input(globalreg, this); notetxt->SetLabel("Note", LABEL_POS_LEFT); notetxt->SetCharFilter(FILTER_ALPHANUMSYM); notetxt->SetTextLen(256); AddComponentVec(notetxt, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); notetxt->Show(); permanent = new Kis_Checkbox(globalreg, this); permanent->SetLabel("Remember note when restarting Kismet"); permanent->SetChecked(1); AddComponentVec(permanent, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); permanent->Show(); okbutton = new Kis_Button(globalreg, this); okbutton->SetLabel("Add Note"); okbutton->Show(); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddNetNoteCB, this); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton->Show(); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetLabel("Cancel"); cancelbutton->Show(); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddNetNoteCB, this); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); delbutton = new Kis_Button(globalreg, this); delbutton->SetLabel("Delete Note"); delbutton->Show(); delbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddNetNoteCB, this); AddComponentVec(delbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(0); bbox->SetCenter(1); bbox->Show(); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(delbutton, 0, 0); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Show(); vbox->Pack_End(notetxt, 0, 0); vbox->Pack_End(permanent, 0, 0); vbox->Pack_End(bbox, 0, 0); main_component = vbox; SetActiveComponent(notetxt); Position(WIN_CENTER(7, 60)); } Kis_AddNetNote_Panel::~Kis_AddNetNote_Panel() { } void Kis_AddNetNote_Panel::DrawPanel() { if (dng == NULL) { if ((dng = kpinterface->FetchMainPanel()->FetchSelectedNetgroup()) == NULL) { kpinterface->RaiseAlert("No network", "Cannot add a note, no network was selected.\n" "Set the Sort type to anything besides Auto-Fit\n" "and highlight a network, then add a note.\n"); kpinterface->KillPanel(this); return; } Netracker::tracked_network *meta = dng->FetchNetwork(); if (meta == NULL) { kpinterface->RaiseAlert("No network", "Cannot add a note, no network was selected.\n" "Set the Sort type to anything besides Auto-Fit\n" "and highlight a network, then add a note.\n"); kpinterface->KillPanel(this); return; } string oldnote = ""; for (map::const_iterator si = meta->arb_tag_map.begin(); si != meta->arb_tag_map.end(); ++si) { if (si->first == "User Note") { oldnote = si->second; break; } } bssid = meta->bssid; notetxt->SetText(oldnote, -1, -1); } Kis_Panel::DrawPanel(); } void Kis_AddNetNote_Panel::Action(Kis_Panel_Component *in_button, int in_state) { if (in_button == cancelbutton) { kpinterface->KillPanel(this); } else if (in_button == delbutton) { if (kpinterface->FetchNetClient() == NULL) { kpinterface->RaiseAlert("No connection", "No longer connected to a Kismet server, cannot\n" "remove a note from a network.\n"); kpinterface->KillPanel(this); return; } kpinterface->FetchNetClient()->InjectCommand("DELNETTAG " + bssid.Mac2String() + " \001User Note\001"); kpinterface->KillPanel(this); } else if (in_button == okbutton) { if (kpinterface->FetchNetClient() == NULL) { kpinterface->RaiseAlert("No connection", "No longer connected to a Kismet server, cannot\n" "add a note to a network.\n"); kpinterface->KillPanel(this); return; } string perm = "0"; if (permanent->GetChecked()) perm = "1"; kpinterface->FetchNetClient()->InjectCommand("ADDNETTAG " + bssid.Mac2String() + " " + perm + " \001User Note\001 " "\001" + notetxt->GetText() + "\001"); kpinterface->KillPanel(this); return; } } int AddCliNoteCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AddCliNote_Panel *) aux)->Action(component, status); return 1; } Kis_AddCliNote_Panel::Kis_AddCliNote_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { cli = NULL; notetxt = new Kis_Single_Input(globalreg, this); notetxt->SetLabel("Note", LABEL_POS_LEFT); notetxt->SetCharFilter(FILTER_ALPHANUMSYM); notetxt->SetTextLen(256); AddComponentVec(notetxt, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); notetxt->Show(); permanent = new Kis_Checkbox(globalreg, this); permanent->SetLabel("Remember note after restarting Kismet"); permanent->SetChecked(1); AddComponentVec(permanent, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); permanent->Show(); okbutton = new Kis_Button(globalreg, this); okbutton->SetLabel("Add Note"); okbutton->Show(); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddCliNoteCB, this); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton->Show(); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetLabel("Cancel"); cancelbutton->Show(); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddCliNoteCB, this); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); delbutton = new Kis_Button(globalreg, this); delbutton->SetLabel("Delete Note"); delbutton->Show(); delbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AddCliNoteCB, this); AddComponentVec(delbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(0); bbox->SetCenter(1); bbox->Show(); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(delbutton, 0, 0); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Show(); vbox->Pack_End(notetxt, 0, 0); vbox->Pack_End(permanent, 0, 0); vbox->Pack_End(bbox, 0, 0); main_component = vbox; SetActiveComponent(notetxt); Position(WIN_CENTER(7, 60)); } Kis_AddCliNote_Panel::~Kis_AddCliNote_Panel() { } void Kis_AddCliNote_Panel::SetClient(Netracker::tracked_client *in_cli) { cli = in_cli; string oldnote = ""; for (map::const_iterator si = cli->arb_tag_map.begin(); si != cli->arb_tag_map.end(); ++si) { if (si->first == "User Note") { oldnote = si->second; break; } } notetxt->SetText(oldnote, -1, -1); } void Kis_AddCliNote_Panel::DrawPanel() { if (cli == NULL) { kpinterface->RaiseAlert("No client", "Cannot add a note, no client was selected.\n" "Set the Sort type to anything besides Auto-Fit\n" "and highlight a client, then add a note.\n"); kpinterface->KillPanel(this); return; } Kis_Panel::DrawPanel(); } void Kis_AddCliNote_Panel::Action(Kis_Panel_Component *in_button, int in_state) { if (in_button == cancelbutton) { kpinterface->KillPanel(this); } else if (in_button == delbutton) { if (kpinterface->FetchNetClient() == NULL) { kpinterface->RaiseAlert("No connection", "No longer connected to a Kismet server, cannot\n" "remove a note from a client.\n"); kpinterface->KillPanel(this); return; } kpinterface->FetchNetClient()->InjectCommand("DELCLITAG " + cli->bssid.Mac2String() + " " + cli->mac.Mac2String() + " \001User Note\001"); kpinterface->KillPanel(this); } else if (in_button == okbutton) { if (kpinterface->FetchNetClient() == NULL) { kpinterface->RaiseAlert("No connection", "No longer connected to a Kismet server, cannot\n" "add a note to a client.\n"); kpinterface->KillPanel(this); return; } if (cli == NULL) { kpinterface->KillPanel(this); return; } string perm = "0"; if (permanent->GetChecked()) perm = "1"; kpinterface->FetchNetClient()->InjectCommand("ADDCLITAG " + cli->bssid.Mac2String() + " " + cli->mac.Mac2String() + " " + perm + " \001User Note\001 \001" + notetxt->GetText() + "\001"); kpinterface->KillPanel(this); return; } } #endif kismet-2013-03-R1b/tcpclient.cc0000664000175000017500000002073612124602454015757 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "tcpclient.h" TcpClient::TcpClient() { fprintf(stderr, "*** TcpClient() called with no global registry reference\n"); } TcpClient::TcpClient(GlobalRegistry *in_globalreg) : NetworkClient(in_globalreg) { // Nothing special here } TcpClient::~TcpClient() { } int TcpClient::Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux) { int ret; connect_complete = -1; connect_cb = in_connect_cb; connect_aux = in_con_aux; if ((client_host = gethostbyname(in_remotehost)) == NULL) { snprintf(errstr, 1024, "TCP client could not resolve host \"%s\"", in_remotehost); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // This doesn't handle connecting to all the different IPs a name could // resolve to. Deal with this in the future. memset(&client_sock, 0, sizeof(client_sock)); client_sock.sin_family = client_host->h_addrtype; memcpy((char *) &client_sock.sin_addr.s_addr, client_host->h_addr_list[0], client_host->h_length); client_sock.sin_port = htons(in_port); if ((cli_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { snprintf(errstr, 1024, "TCP client socket() call failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // fprintf(stderr, "debug - tcpcli socket() %d\n", cli_fd); // Make the buffers read_buf = new RingBuffer(CLI_RING_LEN); write_buf = new RingBuffer(CLI_RING_LEN); // Bind local half memset(&local_sock, 0, sizeof(local_sock)); local_sock.sin_family = AF_INET; local_sock.sin_addr.s_addr = htonl(INADDR_ANY); local_sock.sin_port = htons(0); if (bind(cli_fd, (struct sockaddr *) &local_sock, sizeof(local_sock)) < 0) { snprintf(errstr, 1024, "TCP client bind() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); close(cli_fd); return -1; } // Set it to nonblocking int save_mode = fcntl(cli_fd, F_GETFL, 0); fcntl(cli_fd, F_SETFL, save_mode | O_NONBLOCK); // Connect the sockets if ((ret = connect(cli_fd, (struct sockaddr *) &client_sock, sizeof(client_sock))) < 0) { // fprintf(stderr, "debug - connect %d ret %d\n", cli_fd, ret); if (errno == EINPROGRESS) { // fprintf(stderr, "debug - %d deferred connect started\n", cli_fd); // We haven't completed the connection, set our connect_complete to a // valid value and flag it in write select connect_complete = 0; return 0; } else { close(cli_fd); cli_fd = -1; // Call the connect callback, we failed right off if (connect_cb != NULL) (*connect_cb)(globalreg, errno, connect_aux); return -1; } } else { // fprintf(stderr, "debug - %d connect complete already\n", cli_fd); connect_complete = 1; cl_valid = 1; } // Call the connect callback, we worked right off if (connect_cb != NULL) (*connect_cb)(globalreg, 0, connect_aux); // fprintf(stderr, "debug - TcpClient connected to %s:%hd %d\n", in_remotehost, in_port, cli_fd); return 1; } // Almost the same code as connect, annoying to have it twice, but sometimes // we really need a synchronous connect (like for the client initial connect) int TcpClient::ConnectSync(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux) { int ret; // fprintf(stderr, "debug - tcpclient connect sync\n"); connect_complete = -1; connect_cb = in_connect_cb; connect_aux = in_con_aux; if ((client_host = gethostbyname(in_remotehost)) == NULL) { snprintf(errstr, 1024, "TCP client could not resolve host \"%s\"", in_remotehost); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // This doesn't handle connecting to all the different IPs a name could // resolve to. Deal with this in the future. memset(&client_sock, 0, sizeof(client_sock)); client_sock.sin_family = client_host->h_addrtype; memcpy((char *) &client_sock.sin_addr.s_addr, client_host->h_addr_list[0], client_host->h_length); client_sock.sin_port = htons(in_port); if ((cli_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { snprintf(errstr, 1024, "TCP client socket() call failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // fprintf(stderr, "debug - tcpcli socket() %d\n", cli_fd); // Make the buffers read_buf = new RingBuffer(CLI_RING_LEN); write_buf = new RingBuffer(CLI_RING_LEN); // Bind local half memset(&local_sock, 0, sizeof(local_sock)); local_sock.sin_family = AF_INET; local_sock.sin_addr.s_addr = htonl(INADDR_ANY); local_sock.sin_port = htons(0); if (bind(cli_fd, (struct sockaddr *) &local_sock, sizeof(local_sock)) < 0) { snprintf(errstr, 1024, "TCP client bind() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); close(cli_fd); return -1; } // Connect the sockets if ((ret = connect(cli_fd, (struct sockaddr *) &client_sock, sizeof(client_sock))) < 0) { // fprintf(stderr, "debug - sync connect failed\n"); close(cli_fd); cli_fd = -1; // Call the connect callback, we failed right off if (connect_cb != NULL) (*connect_cb)(globalreg, errno, connect_aux); return -1; } cl_valid = 1; // Set it to nonblocking int save_mode = fcntl(cli_fd, F_GETFL, 0); fcntl(cli_fd, F_SETFL, save_mode | O_NONBLOCK); // fprintf(stderr, "debug - sync connect succeeded\n"); // Call the connect callback, we worked right off if (connect_cb != NULL) (*connect_cb)(globalreg, 0, connect_aux); return 1; } int TcpClient::ReadBytes() { uint8_t recv_bytes[1024]; int ret; // Don't read while we're in connect stage if (connect_complete == 0) return 0; if ((ret = read(cli_fd, recv_bytes, 1024)) < 0) { if (errno == EINTR || errno == EAGAIN) return 0; snprintf(errstr, 1024, "TCP client fd %d read() error: %s", cli_fd, strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (ret <= 0) { snprintf(errstr, 1024, "TCP client fd %d socket closed.", cli_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (read_buf->InsertData(recv_bytes, ret) == 0) { snprintf(errstr, 1024, "TCP client fd %d read error, ring buffer full", cli_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } return ret; } int TcpClient::WriteBytes() { uint8_t dptr[1024]; int dlen, ret; // Don't write while we're in connect stage if (connect_complete == 0) return 0; write_buf->FetchPtr(dptr, 1024, &dlen); if (dlen == 0) { _MSG("TCP client: Client fd " + IntToString(cli_fd) + " got called to " "write data but has no data pending. Check your RegisterPollable calls.", MSGFLAG_ERROR); return 0; } // fprintf(stderr, "debug - %d writing %d bytes\n", cli_fd, dlen); if ((ret = write(cli_fd, dptr, dlen)) <= 0) { if (errno == EINTR || errno == EAGAIN) return 0; // if (errno == EINPROGRESS) fprintf(stderr, "debug - %d ... einprog on write? wtf? ret %d\n", cli_fd, ret); snprintf(errstr, 1024, "TCP client: Killing client fd %d write error %s", cli_fd, strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } write_buf->MarkRead(ret); return ret; } kismet-2013-03-R1b/phy_80211.h0000664000175000017500000001400212124602454015154 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PHY_80211_H__ #define __PHY_80211_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "kis_netframe.h" #include "timetracker.h" #include "filtercore.h" #include "gpscore.h" #include "packet.h" #include "uuid.h" #include "configfile.h" #include "devicetracker.h" /* * 802.11 PHY handlers * Uses new devicetracker code * * Re-implements networktracker, packetdissectors * Ultimately all 802.11 related code will live here, such as alerts, etc. */ enum dot11_ssid_type { dot11_ssid_beacon = 0, dot11_ssid_proberesp = 1, dot11_ssid_probereq = 2, dot11_ssid_file = 3, }; struct dot11_advertised_ssid { dot11_advertised_ssid() { checksum = 0; type = dot11_ssid_beacon; mac = mac_addr(0); ssid = ""; beacon_info = ""; cryptset = 0; ssid_cloaked = 0; first_time = 0; last_time = 0; dirty = 0; maxrate = 0; beaconrate = 0; packets = 0; beacons = 0; dot11d_country = "XXX"; } inline dot11_advertised_ssid& operator= (const dot11_advertised_ssid& in) { checksum = in.checksum; type = in.type; mac = in.mac; ssid = in.ssid; ssid_cloaked = in.ssid_cloaked; beacon_info = in.beacon_info; cryptset = in.cryptset; first_time = in.first_time; last_time = in.last_time; dirty = in.dirty; maxrate = in.maxrate; beaconrate = in.beaconrate; packets = in.packets; beacons = in.beacons; dot11d_country = in.dot11d_country; dot11d_vec = in.dot11d_vec; dirty = in.dirty; return *this; } uint32_t checksum; dot11_ssid_type type; mac_addr mac; string ssid; string beacon_info; // Cryptset and decrypted uint64_t cryptset; // Is the SSID hidden int ssid_cloaked; // First and last times we saw this SSID time_t first_time; time_t last_time; // Advertised maximum rate double maxrate; // Beacon rate in # of beacons per second int beaconrate; // Number of packets seen advertising this ssid int packets; // Number of beacons seen in the last second (for calculating loss) int beacons; string dot11d_country; vector dot11d_vec; // SSID is dirty and should be resent int dirty; }; enum dot11_network_type { dot11_network_ap = 0, dot11_network_adhoc = 1, dot11_network_probe = 2, dot11_network_turbocell = 3, dot11_network_data = 4, dot11_network_mixed = 255, dot11_network_remove = 256 }; // fwd def class dot11_tracked_client; class dot11_tracked_network : public tracker_component { public: dot11_network_type type; mac_addr bssid; string manuf; // Clients associated w/ the network, they're unique/unmasked so // we don't need a macmap map client_map; // Advertised SSID data, by checksum map ssid_map; // Cryptset from data packets not known to be linked to a SSID uint64_t data_cryptset; // One of the SSIDs decrypted? int decrypted; // Best-guess IP kis_ip_data guess_ipdata; // State tracking elements // Number of client disconnects (decayed per second) int client_disconnects; // Last sequence int last_sequence; // Last BSS uint64_t bss_timestamp; // Map of IVs seen, potentially a really bad idea for RAM, should // only be enabled for selected networks map iv_map; // Number of duplicate IVs unsigned int dupeiv_packets; // Do we track IVs on this network? int track_ivs; // CDP data string cdp_dev_id; string cdp_port_id; // Fragments and retries unsigned int fragments; unsigned int retries; // Record is dirty int dirty; // Fields for the client to use void *groupptr; dot11_advertised_ssid *lastssid; // Map of sources which have seen this network // map source_map; }; enum dot11_client_type { dot11_client_unknown = 0, dot11_client_fromds = 1, dot11_client_tods = 2, dot11_client_interds = 3, dot11_client_established = 4, dot11_client_adhoc = 5, dot11_client_remove = 6 }; class dot11_tracked_client : public tracker_component { public: dot11_client_type type; int decrypted; mac_addr bssid; string manuf; int last_sequence; uint64_t data_cryptset; kis_ip_data guess_ipdata; int fragments; int retries; // CDP info string cdp_dev_id, cdp_port_id; // DHCP info string dhcp_host, dhcp_vendor; // Probed SSID data map ssid_map; dot11_tracked_network *netptr; string dot11d_country; vector dot11d_vec; }; class Kis_80211_Phy : public Kis_Phy_Handler { public: // Stub Kis_80211_Phy() { } // Inherited functionality Kis_80211_Phy(GlobalRegistry *in_globalreg) : Kis_Phy_Handler(in_globalreg) { }; // Build a strong version of ourselves virtual Kis_Phy_Handler *CreatePhyHandler(GlobalRegistry *in_globalreg, Devicetracker *in_tracker, int in_phyid) { return new Kis_80211_Phy(in_globalreg, in_tracker, in_phyid); } // Strong constructor Kis_80211_Phy(GlobalRegistry *in_globalreg, Devicetracker *in_tracker, int in_phyid); // Post-dissection packet classifier kicked from Devicetracker virtual int HandlePacket(kis_packet *in_pack); // Timer events passed from Devicetracker virtual int TimerKick(); }; #endif kismet-2013-03-R1b/debian/0000775000175000017500000000000012124602454014675 5ustar dragorndragornkismet-2013-03-R1b/debian/kismet.postrm0000664000175000017500000000106512124602454017441 0ustar dragorndragorn#!/bin/sh -e # Copied from wireshark dpkg & modified GROUP=kismet if [ "$1" = "purge" ] ; then if getent group $GROUP >/dev/null; then if [ -x /usr/sbin/delgroup ]; then echo "Removing kismet group..." delgroup --system $GROUP || echo "Could not remove kismet group." fi fi fi # Automatically added by dh_installdebconf if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule db_purge fi # End automatically added section kismet-2013-03-R1b/debian/rules0000775000175000017500000000176512124602454015766 0ustar dragorndragorn#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # # Modified to make a template file for a multi-binary package with separated # build-arch and build-indep targets by Bill Allombert 2001 # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # This has to be exported to make some magic below work. export DH_OPTIONS %: dh $@ --with autotools-dev --parallel override_dh_auto_build: dh_auto_build $(MAKE) all-plugins override_dh_auto_install: dh_auto_install DESTDIR=$(CURDIR)/debian/tmp $(MAKE) binsuidinstall SUIDGROUP=root DESTDIR=$(CURDIR)/debian/tmp $(MAKE) all-plugins-install override_dh_auto_configure: dh_auto_configure -- --prefix=/usr --sysconfdir=/etc/kismet kismet-2013-03-R1b/debian/README.Debian0000664000175000017500000000030112124602454016730 0ustar dragorndragornkismet for Debian ----------------- -- Mike Kershaw/Dragorn Mon, 31 Dec 2012 19:29:12 +0100 kismet-2013-03-R1b/debian/kismet-plugins-restricted.install0000664000175000017500000000010512124602454023402 0ustar dragorndragorn/usr/lib/kismet/aircrack-kismet.so /usr/lib/kismet/autowep-kismet.so kismet-2013-03-R1b/debian/control0000664000175000017500000000211112124602454016273 0ustar dragorndragornSource: kismet Section: net Priority: optional Maintainer: Mike Kershaw/Dragorn Build-Depends: debhelper (>= 8.0.0), autotools-dev, libncurses5-dev, libpcap0.8-dev (>= 1.0.0), libpcre3-dev, libcap-dev (>= 2.10), libssl-dev, libbluetooth-dev, pkg-config, libnl-3-dev | libnl-dev, libnl-genl-3-dev | libnl-dev Standards-Version: 3.9.3 Homepage: http://www.kismetwireless.net Vcs-Git: https://www.kismetwireless.net/kismet.git Package: kismet Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libcap2-bin Description: Kismet wireless sniffer and IDS Kismet is an 802.11 and other wireless sniffer, logger, and IDS. . This package provides the most recent version, based on the 'newcore' code branch. Package: kismet-plugins-restricted Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Kismet wireless sniffer and IDS, restricted plugins Kismet is an 802.11 and other wireless sniffer, logger, and IDS. . This package contains the 'restricted' plugins, which primarily deal with breaking WEP and other 'aggressive' actions. kismet-2013-03-R1b/debian/kismet.manpages0000664000175000017500000000011312124602454017701 0ustar dragorndragornman/kismet.1 man/kismet_drone.1 man/kismet.conf.5 man/kismet_drone.conf.5 kismet-2013-03-R1b/debian/kismet.postinst0000664000175000017500000000314312124602454017777 0ustar dragorndragorn#!/bin/sh -e # Copied from wireshark-common and modified . /usr/share/debconf/confmodule db_get kismet/install-setuid PROGRAM=/usr/bin/kismet_capture GROUP=kismet if [ -e "$PROGRAM" ]; then if [ "$RET" = "false" ] ; then echo "Not installing Kismet with suid-root capture helper. Kismet " echo "must be run with 'sudo'. This is not the preferred nor most secure way " echo "to install Kismet." if [ -x /usr/sbin/dpkg-statoverride ] && \ ! /usr/sbin/dpkg-statoverride --list $PROGRAM >/dev/null; then chown root:root $PROGRAM chmod u=rwx,go=rx $PROGRAM fi else if [ -x /usr/sbin/dpkg-statoverride ] && \ ! /usr/sbin/dpkg-statoverride --list $PROGRAM >/dev/null; then addgroup --quiet --system $GROUP db_get kismet/install-users if [ "$RET" != "" ]; then for x in ${RET}; do usermod -a -G $GROUP $x done fi chown root:$GROUP $PROGRAM if which setcap > /dev/null ; then echo "Installing Kismet suid-root capture helper and setting capabilities..." chmod u=srwx,g=rx,o=r $PROGRAM if ! setcap cap_net_raw,cap_net_admin=eip $PROGRAM; then echo "Setting capabilities for kismet_capture using Linux Capabilities failed." echo "Falling back to setting set-user-id bit." chmod u=rwxs,g=rx,o=r $PROGRAM fi else echo "Installing Kismet with suid-root capture helper..." chmod u=rwxs,g=rx,o=r $PROGRAM fi fi fi fi kismet-2013-03-R1b/debian/kismet.config0000664000175000017500000000033612124602454017362 0ustar dragorndragorn#! /bin/sh -e . /usr/share/debconf/confmodule db_input critical kismet/install-setuid || true db_go db_get kismet/install-setuid if [ "$RET" != "false" ]; then db_input critical kismet/install-users || true db_go fi kismet-2013-03-R1b/debian/compat0000664000175000017500000000000212124602454016073 0ustar dragorndragorn8 kismet-2013-03-R1b/debian/docs0000664000175000017500000000006412124602454015550 0ustar dragorndragornREADME README.appletv README.win32 RELEASENOTES.txt kismet-2013-03-R1b/debian/kismet.templates0000664000175000017500000000237412124602454020117 0ustar dragorndragorn Template: kismet/install-setuid Type: boolean Default: true Description: Should Kismet be installed to run with setuid privs? Kismet can be installed as setuid (recommended) or as standard (root required). Running Kismet as setuid is recommended over running it as root, because most parts of Kismet (such as the UI and the parts that decode packets) will not run with elevated privileges, reducing the risk of bugs leading to system-wide harm. . For more detailed information, please see the "Suidroot & Security" section of the Kismet README at: http://www.kismetwireless.net/README or /usr/share/doc/kismet/README . Enabling this feature allows users in the 'kismet' group to run Kismet (and capture packets, change wireless card state, etc). Do NOT enable setuid Kismet if you have untrusted users on your system. . Most users running Kismet on personal laptops should install it as setuid. Template: kismet/install-users Type: string Default: Description: Users to add to the kismet group Only users in the kismet group are able to use kismet under the setuid model. . List users, separated by spaces, to be added to the group. . NOTE: After adding users to a group, typically they must log out and log in again before the group is recognized. kismet-2013-03-R1b/debian/README.source0000664000175000017500000000027712124602454017062 0ustar dragorndragornkismet for Debian ----------------- kismet-2013-03-R1b/debian/source/0000775000175000017500000000000012124602454016175 5ustar dragorndragornkismet-2013-03-R1b/debian/source/format0000664000175000017500000000001512124602454017404 0ustar dragorndragorn3.0 (native) kismet-2013-03-R1b/debian/changelog0000664000175000017500000000045412124602454016552 0ustar dragorndragornkismet (2013.03.1) unstable; urgency=low * 2013.03.R1 release -- Kismet Release Mon, 18 Mar 2013 19:00:00 -0500 kismet (2013.0.0) unstable; urgency=low * Git build. -- Kismet Release Mon, 31 Dec 2012 19:29:12 +0100 kismet-2013-03-R1b/debian/kismet.install0000664000175000017500000000045112124602454017561 0ustar dragorndragorn/usr/bin/kismet /usr/bin/kismet_capture /usr/bin/kismet_client /usr/bin/kismet_drone /usr/bin/kismet_server /usr/lib/kismet/btscan.so /usr/lib/kismet/spectool_net.so /usr/lib/kismet_client/spectools_ui.so /usr/lib/kismet_client/btscan_ui.so /etc/kismet/kismet*.conf /usr/share/kismet/wav/*.wav kismet-2013-03-R1b/debian/README0000664000175000017500000000025712124602454015561 0ustar dragorndragornThe Debian Package kismet ---------------------------- Comments regarding the Package -- Mike Kershaw/Dragorn Mon, 31 Dec 2012 19:29:12 +0100 kismet-2013-03-R1b/debian/copyright0000664000175000017500000004400012124602454016626 0ustar dragorndragornFormat: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: kismet Source: Files: * Copyright: License: GPL-2.0+ Files: debian/* Copyright: 2012 Mike Kershaw/Dragorn License: GPL-2.0+ License: GPL-2.0+ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program 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 2 of the License, or (at your option) any later version. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. $Id: GPL,v 1.1 2002/07/22 15:01:27 dragorn Exp $ kismet-2013-03-R1b/ifcontrol.h0000664000175000017500000000620412124602454015625 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __IFCONTROL_H__ #define __IFCONTROL_H__ #include "config.h" #include #include #include #include #include #ifdef SYS_LINUX #include #include #else #include #endif #ifndef SYS_CYGWIN #include #include #include #include #include #endif #ifdef SYS_NETBSD #include #include #endif #include "util.h" #if defined(SYS_LINUX) || defined(SYS_NETBSD) || defined(SYS_OPENBSD) || \ defined(SYS_FREEBSD) || defined(SYS_DARWIN) int Ifconfig_Set_Flags(const char *in_dev, char *errstr, int flags); int Ifconfig_Delta_Flags(const char *in_dev, char *errstr, int flags); int Ifconfig_Get_Flags(const char *in_dev, char *errstr, int *flags); #endif #ifdef SYS_LINUX int Ifconfig_Get_Hwaddr(const char *in_dev, char *errstr, uint8_t *ret_hwaddr); int Ifconfig_Set_Hwaddr(const char *in_dev, char *errstr, uint8_t *in_hwaddr); int Ifconfig_Set_MTU(const char *in_dev, char *errstr, uint16_t in_mtu); // Definitions gratuitiously yoinked from ethtool-2 for getting // driver info #define ETHTOOL_BUSINFO_LEN 32 struct ethtool_drvinfo { uint32_t cmd; char driver[32]; // Driver short name char version[32]; // Driver version char fw_version[32]; // Driver firmware version // We don't really care about anything below here but we need it // anyhow. char bus_info[ETHTOOL_BUSINFO_LEN]; // Bus info char reserved1[32]; char reserved2[16]; uint32_t n_stats; // Number of ETHTOOL_GSTATS uint32_t testinfo_len; uint32_t eedump_len; // Size of ETHTOOL_GEEPROM uint32_t regdump_len; }; #ifndef ETHTOOL_GDRVINFO #define ETHTOOL_GDRVINFO 0x00000003 #endif #ifndef SIOCETHTOOL #define SIOCETHTOOL 0x8946 #endif // Get the ethtool info int Linux_GetDrvInfo(const char *in_dev, char *errstr, struct ethtool_drvinfo *info); string Linux_GetSysDrv(const char *in_dev); int Linux_GetSysDrvAttr(const char *in_dev, const char *in_attr); int Ifconfig_Get_Hwaddr(const char *in_dev, char *errstr, uint8_t *ret_hwaddr); int Ifconfig_Set_Hwaddr(const char *in_dev, char *errstr, uint8_t *in_hwaddr); int Ifconfig_Set_MTU(const char *in_dev, char *errstr, uint16_t in_mtu); int Ifconfig_Set_IP(const char *in_dev, char *errstr, const char *ip); int Ifconfig_Set_Netmask(const char *in_dev, char *errstr, const char *netmask); #endif #endif kismet-2013-03-R1b/plugintracker.h0000664000175000017500000001263012124602454016500 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PLUGINTRACKER_H__ #define __PLUGINTRACKER_H__ // Plugin handler core // // Handles scanning the config file, stocking the vector of plugins with root // and nonroot plugins, getting the plugin info from the shared object, and // calling the various plugin handler hooks. // // This is fairly platform specific -- posix systems should all be able to use // the dlopen/dlsym/dlclose system, but it will have to be turned into // native code on win32 if we ever port there // // PLUGIN AUTHORS: This is the Kismet internal tracking system that handles // plugins. All you need to worry about is filling in the plugin_usrdata struct // and returning the proper info for register/unregister. // // PLUGIN VERSIONING: Plugins should define a kis_plugin_info(...) function // (as defined below) which fills in the supplied struct with the version_major, // version_minor, and version_tiny of the *kismet* versions the plugin was compiled // with. These are used to make sure that the plugin is running in a sane environment. // // Plugins which operate as root WILL NOT be able to perform root actions after // the privdrop has occured. Currently there are no hooks to modularize the // server/rootpid system, this may change if needed in the future. Open any // files and sockets you need before the drop. #include "config.h" #include #include #include #include #include #include #include #include #include #include "globalregistry.h" // Generic plugin function hook typedef int (*plugin_hook)(GlobalRegistry *); // This struct is passed to a plugin to be filled in with all their info struct plugin_usrdata { // Basic info about the plugin string pl_name; string pl_description; string pl_version; // Can this plugin be unloaded? Anything that touches capture sources // should definitely say no, and anything else that sets up dynamic // structures that can't be reasonably disassembled or recreated should // answer no. Unloadable plugins should still handle the unload event in // a permanent fashion, this just means Kismet will not ask it to unload // during runtime. int pl_unloadable; // Call back to initialized. A 0 return means "try again later in the build // chain", a negative means "failure" and a positive means success. plugin_hook plugin_register; // Callback to be removed plugin_hook plugin_unregister; }; // Plugin information fetch function typedef int (*plugin_infocall)(plugin_usrdata *); // Plugin version information, v1 // This holds revision information for the KISMET THE PLUGIN WAS COMPILED WITH, // NOT THE PLUGIN VERSION (plugin version is passed in the info struct!) struct plugin_revision { // V1 data // Versioned for possible updates to the version api int version_api_revision; string major; string minor; string tiny; // End V1 data }; #define KIS_PLUGINTRACKER_VREVISION 1 // Plugin revision call. If the kis_plugin_revision symbol is available in the plugin, // then it will be passed an allocated plugin_revision struct, with the version_api_rev // set appropriately. Plugins MUST ONLY use fields in the negotiated plugin version // record. This record is not expected to change significantly over time, BUT IT MAY, // should it become necessary to add more complex data. typedef void (*plugin_revisioncall)(plugin_revision *); // Plugin management class class Plugintracker { public: struct plugin_meta { plugin_meta() { dlfileptr = NULL; activate = 0; root = 0; infosym = NULL; }; // Path to plugin string filename; // Object name of the plugin string objectname; // Pointer to dlopened file void *dlfileptr; // Plugin has successfully activated? int activate; // Plugin is activated as root? int root; // Data from the plugin plugin_usrdata usrdata; // Info symbol plugin_infocall infosym; }; static void Usage(char *name); Plugintracker(); Plugintracker(GlobalRegistry *in_globalreg); virtual ~Plugintracker(); // Parse the config file and load root plugins into the vector int ScanRootPlugins(); // Scan the plugins directories and load all the found plugins for userspace int ScanUserPlugins(); // Activate the vector of plugins (called repeatedly during startup) int ActivatePlugins(); // Last chance for plugins to activate or we error out int LastChancePlugins(); // Shut down the plugins and close the shared files int ShutdownPlugins(); // Network hook to send the plugins to a user on enable int BlitPlugins(int in_fd); protected: GlobalRegistry *globalreg; int plugins_active; int ScanDirectory(DIR *in_dir, string in_path); vector plugin_vec; int plugins_protoref; }; #endif kismet-2013-03-R1b/nl80211_control.cc0000664000175000017500000003363112124602454016535 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #if defined(HAVE_LIBNL20) || defined(HAVE_LIBNL30) #define HAVE_LIBNL_NG #endif #ifdef SYS_LINUX #ifdef HAVE_LINUX_NETLINK #include #include #include #include #include #include #include #include #include #include "nl80211.h" #include #endif #include #include #include #include #include #include "util.h" #include "nl80211_control.h" // Libnl1->Libnl2 compatability mode since the API changed, cribbed from 'iw' #if !defined(HAVE_LIBNL_NG) #define nl_sock nl_handle static inline struct nl_handle *nl_socket_alloc(void) { return nl_handle_alloc(); } static inline void nl_socket_free(struct nl_sock *h) { nl_handle_destroy(h); } static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache) { struct nl_cache *tmp = genl_ctrl_alloc_cache(h); if (!tmp) return -1; *cache = tmp; return 0; } #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache #endif int mac80211_connect(const char *interface, void **handle, void **cache, void **family, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); return -1; #else struct nl_sock *nl_handle; struct nl_cache *nl_cache; struct genl_family *nl80211; if (*handle == NULL) { if ((nl_handle = nl_socket_alloc()) == NULL) { snprintf(errstr, STATUS_MAX, "%s failed to allocate nlhandle", __FUNCTION__); return -1; } if (genl_connect(nl_handle)) { snprintf(errstr, STATUS_MAX, "%s failed to connect to generic netlink %s", __FUNCTION__, strerror(errno)); nl_socket_free(nl_handle); return -1; } } else { nl_handle = (struct nl_sock *) (*handle); } if (genl_ctrl_alloc_cache(nl_handle, &nl_cache) != 0) { snprintf(errstr, STATUS_MAX, "%s failed to allocate generic netlink cache", __FUNCTION__); nl_socket_free(nl_handle); return -1; } if ((nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211")) == NULL) { snprintf(errstr, STATUS_MAX, "%s failed to find nl80211 controls, " "kernel may be too old", __FUNCTION__); nl_socket_free(nl_handle); return -1; } (*handle) = (void *) nl_handle; (*cache) = (void *) nl_cache; (*family) = (void *) nl80211; return 1; #endif } void mac80211_disconnect(void *handle) { #ifdef HAVE_LINUX_NETLINK nl_socket_free((nl_sock *) handle); #endif } int mac80211_createvap(const char *interface, const char *newinterface, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); return -1; #else struct nl_sock *nl_handle = NULL; struct nl_cache *nl_cache = NULL; struct genl_family *nl80211 = NULL; struct nl_msg *msg; if (if_nametoindex(newinterface) > 0) return 1; if (mac80211_connect(interface, (void **) &nl_handle, (void **) &nl_cache, (void **) &nl80211, errstr) < 0) return -1; if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, STATUS_MAX, "mac80211_createvap() failed to allocate " "message"); mac80211_disconnect(nl_handle); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, newinterface); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); if (nl_send_auto_complete(nl_handle, msg) < 0 || nl_wait_for_ack(nl_handle) < 0) { nla_put_failure: snprintf(errstr, STATUS_MAX, "mac80211_createvap() failed to create " "interface '%s'", newinterface); nlmsg_free(msg); mac80211_disconnect(nl_handle); return -1; } nlmsg_free(msg); mac80211_disconnect(nl_handle); if (if_nametoindex(newinterface) <= 0) { snprintf(errstr, STATUS_MAX, "mac80211_createvap() thought we made a vap, " "but it wasn't there when we looked"); return -1; } return 0; #endif } // Has to be a separate function because of gotos, ew void mac80211_parseflags(vector in_flags, struct nl_msg *msg) { #ifdef HAVE_LINUX_NETLINK struct nl_msg *flags; enum nl80211_mntr_flags flag = NL80211_MNTR_FLAG_MAX; if ((flags = nlmsg_alloc()) == NULL) { return; } for (unsigned int x = 0; x < in_flags.size(); x++) { switch (in_flags[x]) { case nl80211_mntr_flag_none: continue; break; case nl80211_mntr_flag_fcsfail: flag = NL80211_MNTR_FLAG_FCSFAIL; break; case nl80211_mntr_flag_plcpfail: flag = NL80211_MNTR_FLAG_PLCPFAIL; break; case nl80211_mntr_flag_control: flag = NL80211_MNTR_FLAG_CONTROL; break; case nl80211_mntr_flag_otherbss: flag = NL80211_MNTR_FLAG_OTHER_BSS; break; case nl80211_mntr_flag_cookframe: flag = NL80211_MNTR_FLAG_COOK_FRAMES; break; } NLA_PUT_FLAG(flags, flag); } nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); nla_put_failure: nlmsg_free(flags); #endif } int mac80211_setvapflag(const char *interface, vector in_flags, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); return -1; #else struct nl_sock *nl_handle = NULL; struct nl_cache *nl_cache = NULL; struct genl_family *nl80211 = NULL; struct nl_msg *msg = NULL; if (mac80211_connect(interface, (void **) &nl_handle, (void **) &nl_cache, (void **) &nl80211, errstr) < 0) return -1; if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, STATUS_MAX, "%s failed to allocate message", __FUNCTION__); mac80211_disconnect(nl_handle); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_SET_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); mac80211_parseflags(in_flags, msg); if (nl_send_auto_complete(nl_handle, msg) >= 0) { if (nl_wait_for_ack(nl_handle) < 0) { goto nla_put_failure; } } else { nla_put_failure: snprintf(errstr, STATUS_MAX, "%s failed to set flags on " "interface '%s': %s", __FUNCTION__, interface, strerror(errno)); nlmsg_free(msg); mac80211_disconnect(nl_handle); return -1; } nlmsg_free(msg); mac80211_disconnect(nl_handle); return 0; #endif } int mac80211_setchannel_cache(const char *interface, void *handle, void *family, int channel, unsigned int chmode, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); // Return the same error as we get if the device doesn't support nlfreq return -22; #else struct nl_sock *nl_handle = (struct nl_sock *) handle; struct genl_family *nl80211 = (struct genl_family *) family; struct nl_msg *msg; int ret = 0; int chanmode[] = { NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, NL80211_CHAN_HT40PLUS, NL80211_CHAN_HT40MINUS }; if (chmode > 4) { snprintf(errstr, STATUS_MAX, "Invalid channel mode\n"); return -1; } if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, STATUS_MAX, "mac80211_setchannel() failed to allocate " "message"); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_SET_WIPHY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, ChanToFreq(channel)); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chanmode[chmode]); if ((ret = nl_send_auto_complete(nl_handle, msg)) >= 0) { if ((ret = nl_wait_for_ack(nl_handle)) < 0) goto nla_put_failure; } nlmsg_free(msg); return 0; nla_put_failure: snprintf(errstr, STATUS_MAX, "mac80211_setchannel() could not set channel " "%d/%d on interface '%s' err %d", channel, ChanToFreq(channel), interface, ret); nlmsg_free(msg); return ret; #endif } int mac80211_setchannel(const char *interface, int channel, unsigned int chmode, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); // Return the same error as if the device doesn't support nl freq control // so we catch it elsewhere return -22; #else struct nl_sock *nl_handle = NULL; struct nl_cache *nl_cache = NULL; struct genl_family *nl80211 = NULL; if (mac80211_connect(interface, (void **) &nl_handle, (void **) &nl_cache, (void **) &nl80211, errstr) < 0) return -1; int ret = mac80211_setchannel_cache(interface, (void *) nl_handle, (void *) nl80211, channel, chmode, errstr); mac80211_disconnect(nl_handle); return ret; #endif } #ifdef HAVE_LINUX_NETLINK static int mac80211_freqlist_cb(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; struct nlattr *nl_band, *nl_freq; int rem_band, rem_freq; uint32_t freq; mac80211_channel_block *chanb = (mac80211_channel_block *) arg; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) { return NL_SKIP; } if (tb_msg[NL80211_ATTR_WIPHY_NAME]) { if (strcmp(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]), chanb->phyname.c_str()) != 0) { return NL_SKIP; } } for (nl_band = (struct nlattr *) nla_data(tb_msg[NL80211_ATTR_WIPHY_BANDS]), rem_band = nla_len(tb_msg[NL80211_ATTR_WIPHY_BANDS]); nla_ok(nl_band, rem_band); nl_band = (struct nlattr *) nla_next(nl_band, &rem_band)) { nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), nla_len(nl_band), NULL); for (nl_freq = (struct nlattr *) nla_data(tb_band[NL80211_BAND_ATTR_FREQS]), rem_freq = nla_len(tb_band[NL80211_BAND_ATTR_FREQS]); nla_ok(nl_freq, rem_freq); nl_freq = (struct nlattr *) nla_next(nl_freq, &rem_freq)) { nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (struct nlattr *) nla_data(nl_freq), nla_len(nl_freq), NULL); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) continue; freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); if (freq == 0) continue; chanb->channel_list.push_back(FreqToChan(freq)); } } return NL_SKIP; } #endif #ifdef HAVE_LINUX_NETLINK static int mac80211_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = (int *) arg; *ret = err->error; return NL_STOP; } static int mac80211_finish_cb(struct nl_msg *msg, void *arg) { int *ret = (int *) arg; *ret = 0; return NL_SKIP; } #endif int mac80211_get_chanlist(const char *interface, vector *chan_list, char *errstr) { mac80211_channel_block cblock; #ifndef HAVE_LINUX_NETLINK snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 " "support, check the output of ./configure for why"); return MAC80211_CHANLIST_NOT_MAC80211; #else void *handle = NULL, *cache = NULL, *family = NULL; struct nl_cb *cb; int err; struct nl_msg *msg; cblock.phyname = mac80211_find_parent(interface); if (cblock.phyname == "") { if (if_nametoindex(interface) <= 0) { snprintf(errstr, STATUS_MAX, "Interface %s doesn't exist", interface); return MAC80211_CHANLIST_NO_INTERFACE; } snprintf(errstr, STATUS_MAX, "Kismet could not find a parent phy device " "for interface %s, it isn't mac80211?", interface); return MAC80211_CHANLIST_NOT_MAC80211; } if (mac80211_connect(interface, &handle, &cache, &family, errstr) < 0) { return MAC80211_CHANLIST_GENERIC; } msg = nlmsg_alloc(); cb = nl_cb_alloc(NL_CB_DEFAULT); err = 1; nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, mac80211_freqlist_cb, &cblock); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, mac80211_finish_cb, &err); nl_cb_err(cb, NL_CB_CUSTOM, mac80211_error_cb, &err); genlmsg_put(msg, 0, 0, genl_family_get_id((struct genl_family *) family), 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0); if (nl_send_auto_complete((struct nl_sock *) handle, msg) < 0) { snprintf(errstr, STATUS_MAX, "%s: Failed to write nl80211 message", __FUNCTION__); mac80211_disconnect(handle); return MAC80211_CHANLIST_GENERIC; } while (err) nl_recvmsgs((struct nl_sock *) handle, cb); mac80211_disconnect(handle); (*chan_list) = cblock.channel_list; return cblock.channel_list.size(); #endif } string mac80211_find_parent(const char *interface) { DIR *devdir; struct dirent *devfile; string dirpath; dirpath = string("/sys/class/net/") + interface + string("/phy80211/device"); if ((devdir = opendir(dirpath.c_str())) == NULL) return ""; while ((devfile = readdir(devdir)) != NULL) { if (strlen(devfile->d_name) < 13) continue; if (strncmp("ieee80211:phy", devfile->d_name, 13) == 0) { string dev = string(devfile->d_name + 10); closedir(devdir); return dev; } } closedir(devdir); return ""; } #endif /* linux */ kismet-2013-03-R1b/gpsserial.cc0000664000175000017500000002453212124602454015761 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "gpsserial.h" #include "configfile.h" #include "soundcontrol.h" #include "packetchain.h" int SerialGpsEvent(Timetracker::timer_event *evt, void *parm, GlobalRegistry *globalreg) { GPSSerial *gps = (GPSSerial *) parm; return gps->Timer(); } GPSSerial::GPSSerial() { fprintf(stderr, "FATAL OOPS: gpsserial called with no globalreg\n"); exit(-1); } GPSSerial::GPSSerial(GlobalRegistry *in_globalreg) : GPSCore(in_globalreg) { // Make a serial port object sercli = new SerialClient(globalreg); netclient = sercli; last_disconnect = 0; last_hed_time = 0; // Attach it to ourselves and opposite RegisterNetworkClient(sercli); sercli->RegisterClientFramework(this); if (globalreg->kismet_config->FetchOpt("gpsdevice") == "") { _MSG("Missing 'gpsdevice' option in config, but gpstype set to serial", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } ScanOptions(); RegisterComponents(); gpseventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &SerialGpsEvent, (void *) this); snprintf(device, 128, "%s", globalreg->kismet_config->FetchOpt("gpsdevice").c_str()); if (Reconnect() < 0) return; last_mode = -1; if (last_disconnect == 0) _MSG("Using GPS device on " + string(device), MSGFLAG_INFO); } GPSSerial::~GPSSerial() { // Unregister ourselves from the main tcp service loop globalreg->RemovePollableSubsys(this); } int GPSSerial::Shutdown() { if (sercli != NULL) { sercli->FlushRings(); sercli->KillConnection(); } return 1; } int GPSSerial::Reconnect() { if (sercli->Connect(device, 0, NULL, NULL) < 0) { _MSG("GPSSerial: Could not open serial port " + string(device), MSGFLAG_ERROR); if (reconnect_attempt < 0) { _MSG("GPSSerial: Reconnection not enabled (gpsreconnect), disabling " "GPS", MSGFLAG_ERROR); last_disconnect = globalreg->timestamp.tv_sec; gps_connected = 0; return 0; } } // Reset the device options struct termios options; sercli->GetOptions(&options); options.c_oflag = 0; options.c_iflag = 0; options.c_iflag &= (IXON | IXOFF | IXANY); options.c_cflag |= CLOCAL | CREAD; options.c_cflag &= ~HUPCL; cfsetispeed(&options, B4800); cfsetospeed(&options, B4800); sercli->SetOptions(TCSANOW, &options); last_hed_time = 0; reconnect_attempt = 1; last_disconnect = 0; Timer(); return 1; } int GPSSerial::ParseData() { int len, rlen; char *buf; double in_lat = 0, in_lon = 0, in_spd = 0, in_alt = 0; int in_mode = 0, set_data = 0, set_spd = 0, set_mode = 0; if (netclient == NULL) return 0; if (netclient->Valid() == 0) return 0; len = netclient->FetchReadLen(); buf = new char[len + 1]; if (netclient->ReadData(buf, len, &rlen) < 0) { _MSG("GPSSerial parser failed to get data from the serial port", MSGFLAG_ERROR); return -1; } buf[len] = '\0'; vector inptok = StrTokenize(buf, "\n", 0); delete[] buf; if (inptok.size() < 1) { return 0; } set_data = 0; set_spd = 0; set_mode = 0; for (unsigned int it = 0; it < inptok.size(); it++) { if (netclient->Valid()) { netclient->MarkRead(inptok[it].length() + 1); } // If we've seen anything off the serial declare that we've seen the // gps in some state so we report that we have one gps_ever_lock = 1; if (inptok[it].length() < 4) continue; // $GPGGA,012527.000,4142.6918,N,07355.8711,W,1,07,1.2,57.8,M,-34.0,M,,0000*57 vector gpstoks = StrTokenize(inptok[it], ","); if (gpstoks.size() == 0) continue; if (gpstoks[0] == "$GPGGA") { int tint; float tfloat; gps_connected = 1; if (gpstoks.size() < 15) continue; // Parse the basic gps coodinate string // $GPGGA,time,lat,NS,lon,EW,quality,#sats,hdop,alt,M,geopos,M, // dgps1,dgps2,checksum if (sscanf(gpstoks[2].c_str(), "%2d%f", &tint, &tfloat) != 2) continue; in_lat = (float) tint + (tfloat / 60); if (gpstoks[3] == "S") in_lat = in_lat * -1; if (sscanf(gpstoks[4].c_str(), "%3d%f", &tint, &tfloat) != 2) continue; in_lon = (float) tint + (tfloat / 60); if (gpstoks[5] == "W") in_lon = in_lon * -1; if (sscanf(gpstoks[9].c_str(), "%f", &tfloat) != 1) continue; in_alt = tfloat; // printf("debug - %f, %f alt %f\n", in_lat, in_lon, in_alt); set_data = 1; continue; } if (gpstoks[0] == "$GPRMC") { // recommended minimum // $GPRMC,time,valid,lat,lathemi,lon,lonhemi,speed-knots,bearing,utc,,checksum int tint; float tfloat; gps_connected = 1; if (gpstoks.size() < 12) continue; if (gpstoks[2] == "A") { // Kluge - if we have a 3d fix, we're getting another sentence // which contains better information, so we don't override it. // If we < a 2d fix, we up it to 2d. if (last_mode < 3) { in_mode = 2; set_mode = 1; } } else { continue; } if (sscanf(gpstoks[3].c_str(), "%2d%f", &tint, &tfloat) != 2) continue; in_lat = (float) tint + (tfloat / 60); if (gpstoks[4] == "S") in_lat = in_lat * -1; if (sscanf(gpstoks[5].c_str(), "%3d%f", &tint, &tfloat) != 2) continue; in_lon = (float) tint + (tfloat / 60); if (gpstoks[6] == "W") in_lon = in_lon * -1; if (sscanf(gpstoks[7].c_str(), "%f", &tfloat) != 1) continue; in_spd = tfloat; set_spd = 1; // Inherit the altitude we had before since this sentence doesn't // have any alt records in_alt = alt; // printf("debug - %f, %f spd %f\n", in_lat, in_lon, in_spd); set_data = 1; continue; } // GPS DOP and active sats if (gpstoks[0] == "$GPGSA") { /* http://www.gpsinformation.org/dale/nmea.htm#GSA $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39 Where: GSA Satellite status A Auto selection of 2D or 3D fix (M = manual) 3 3D fix - values include: 1 = no fix 2 = 2D fix 3 = 3D fix 04,05... PRNs of satellites used for fix (space for 12) 2.5 PDOP (dilution of precision) 1.3 Horizontal dilution of precision (HDOP) 2.1 Vertical dilution of precision (VDOP) *39 the checksum data, always begins with * */ int tint; gps_connected = 1; if (gpstoks.size() < 18) continue; if (sscanf(gpstoks[2].c_str(), "%d", &tint) != 1) continue; /* Account for jitter after the first set */ if (tint >= last_mode) { in_mode = tint; last_mode = tint; set_mode = 1; // printf("debug - mode %d\n", in_mode); } else { last_mode = tint; } } // Travel made good if (gpstoks[0] == "$GPVTG") { // $GPVTG,,T,,M,0.00,N,0.0,K,A*13 float tfloat; if (gpstoks.size() < 10) { continue; } if (set_spd == 0) { if (sscanf(gpstoks[7].c_str(), "%f", &tfloat) != 1) continue; in_spd = tfloat; set_spd = 1; } continue; } else if (inptok[it].substr(0, 6) == "$GPGSV") { // $GPGSV,3,1,09,22,80,170,40,14,58,305,19,01,46,291,,18,44,140,33*7B // $GPGSV,3,2,09,05,39,105,31,12,34,088,32,30,31,137,31,09,26,047,34*72 // $GPGSV,3,3,09,31,26,222,31*46 // // # of sentences for data // sentence # // # of sats in view // // sat # // elevation // azimuth // snr vector svvec = StrTokenize(inptok[it], ","); GPSCore::sat_pos sp; gps_connected = 1; if (svvec.size() < 6) { continue; } // If we're on the last sentence, move the new vec to the transmitted one if (svvec[1] == svvec[2]) { sat_pos_map = sat_pos_map_tmp; sat_pos_map_tmp.clear(); } unsigned int pos = 4; while (pos + 4 < svvec.size()) { if (sscanf(svvec[pos++].c_str(), "%d", &sp.prn) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.elevation) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.azimuth) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.snr) != 1) sp.snr = 0; sat_pos_map_tmp[sp.prn] = sp; } continue; } } if (set_data) { last_lat = lat; lat = in_lat; last_lon = lon; lon = in_lon; alt = in_alt; last_hed = hed; hed = CalcHeading(lat, lon, last_lat, last_lon); } if (set_mode) { if (mode < 2 && (gps_options & GPSD_OPT_FORCEMODE)) { mode = 2; } else { if (mode < 2 && in_mode >= 2) { globalreg->soundctl->SayText("Got G P S position fix"); globalreg->soundctl->PlaySound("gpslock"); } else if (mode >= 2 && in_mode < 2) { globalreg->soundctl->SayText("Lost G P S position fix"); globalreg->soundctl->PlaySound("gpslost"); } mode = in_mode; } } // This is always in knots from nmea, convert to meters/sec like gpsd uses */ if (set_spd) spd = in_spd * 0.514; if (set_data) { if (last_hed_time == 0) { last_hed_time = globalreg->timestamp.tv_sec; } else if (globalreg->timestamp.tv_sec - last_hed_time > 1) { // It's been more than a second since we updated the heading, so we // can back up the lat/lon and do hed calcs last_lat = lat; last_lon = lon; last_hed = hed; hed = CalcHeading(in_lat, in_lon, last_lat, last_lon); last_hed_time = globalreg->timestamp.tv_sec; } } return 1; } int GPSSerial::Timer() { // fprintf(stderr, "debug - serial timer valid %d attempt %d last time %d\n", netclient->Valid(), reconnect_attempt, last_disconnect); // Timed backoff up to 30 seconds if (netclient->Valid() == 0 && reconnect_attempt >= 0 && (globalreg->timestamp.tv_sec - last_disconnect >= (kismin(reconnect_attempt, 6) * 5))) { // fprintf(stderr, "debug - serial reconnect?\n"); if (Reconnect() <= 0) return 1; } GPSCore::Timer(); return 1; } kismet-2013-03-R1b/kis_clinetframe.h0000664000175000017500000001214212124602454016763 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISCLINETFRAME_H__ #define __KISCLINETFRAME_H__ #include "config.h" #include "util.h" #include "messagebus.h" #include "clinetframework.h" #include "tcpclient.h" class KisNetClient; #define CLIPROTO_CB_PARMS GlobalRegistry *globalreg, string proto_string, \ vector *proto_parsed, KisNetClient *srccli, void *auxptr typedef void (*CliProto_Callback)(CLIPROTO_CB_PARMS); #define CLICONF_CB_PARMS GlobalRegistry *globalreg, KisNetClient *kcli, \ int recon, void *auxptr typedef void (*CliConf_Callback)(CLICONF_CB_PARMS); #define CLICMD_CB_PARMS GlobalRegistry *globalreg, KisNetClient *kcli, \ int valid, string response, void *auxptr typedef void (*CliCmd_Callback)(CLICMD_CB_PARMS); class KisNetClient : public ClientFramework { public: KisNetClient(); KisNetClient(GlobalRegistry *in_globalreg); virtual ~KisNetClient(); // Connect to a server string, proto://host:port virtual int Connect(string in_host, int in_reconnect); virtual string FetchHost() { return host; } virtual int FetchPort() { return port; } virtual void AddConfCallback(CliConf_Callback in_cb, int in_recon, void *in_aux); virtual void RemoveConfCallback(CliConf_Callback in_cb); virtual int FetchConfigured() { return configured; } virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set &in_rset, fd_set &in_wset) { return netclient->Poll(in_rset, in_wset); } virtual int ParseData(); virtual int KillConnection(); virtual int Shutdown(); virtual void ConnectCB(int status); // Register a handler for a protocol. There can be multiple handlers. virtual int RegisterProtoHandler(string in_proto, string in_fieldlist, CliProto_Callback in_cb, void *in_aux, CliCmd_Callback in_cmd_complete = NULL); virtual void RemoveProtoHandler(string in_proto, CliProto_Callback in_cb, void *in_aux); // Grab the list of fields we know about for a proto so clients can // request what they want virtual int FetchProtoCapabilities(string in_proto, map *ret_fields); // Inject a command, with optional callbacks that will trigger when it // completes with a success or fail virtual int InjectCommand(string in_cmdtext, CliCmd_Callback in_cb = NULL, void *in_aux = NULL); // Cancel all pending command callbacks referencing a specific cb/ptr // (used when shutting down a receiver to make sure no existing callbacks // can be triggered after the rx is destroyed) virtual void RemoveAllCmdCallbacks(CliCmd_Callback in_cb, void *in_aux); virtual int Reconnect(); virtual int Timer(); virtual string FetchServerName() { return server_name; } virtual int FetchServerUid() { return server_uid; } virtual time_t FetchServerStarttime() { return server_starttime; } // Internal callback handler record struct kcli_handler_rec { void *auxptr; CliProto_Callback callback; // Vector of LOCAL field nums (as processed by the interim // handler) vector local_fnums; }; // Absolute field numbers to configured field numbers map, and callback // list struct kcli_configured_proto_rec { // Fields we enable string fields; map abs_to_conf_fnum_map; vector handler_vec; }; // Internal conf cb record struct kcli_conf_rec { void *auxptr; CliConf_Callback callback; int on_recon; }; // Absolute field numbers and names from the CAPABILITY list struct kcli_field_rec { string fname; int fnum; int usecount; }; struct kcli_cmdcb_rec { void *auxptr; CliCmd_Callback callback; }; protected: TcpClient *tcpcli; char host[MAXHOSTNAMELEN]; short int port; // Callbacks to call when we get configured vector conf_cb_vec; // Double map of protocols and fields in them, filled in at connection time map > proto_field_dmap; // Map of protocols to handlers map handler_cb_map; // Map of command callback events map command_cb_map; int reconnect; int reconid, timerid; // Have we gotten configure data for everything? int configured; int cmdid; time_t last_disconnect, time_connected, last_read; int num_reconnects; time_t last_time; // Server start time & uid and such time_t server_starttime; string server_name; int server_uid; }; #endif kismet-2013-03-R1b/devicetracker.h0000664000175000017500000003355612124602454016453 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DEVICE_TRACKER_H__ #define __DEVICE_TRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "kis_netframe.h" #include "timetracker.h" #include "filtercore.h" #include "gpscore.h" #include "packet.h" #include "uuid.h" #include "configfile.h" // How big the main vector of components is, if we ever get more than this // many tracked components we'll need to expand this but since it ties to // memory and track record creation it starts relatively low #define MAX_TRACKER_COMPONENTS 64 #define KIS_PHY_ANY -1 #define KIS_PHY_UNKNOWN -2 // Basic unit being tracked in a tracked device class tracker_component { public: tracker_component() { self_destruct = 1; } virtual ~tracker_component() { } int self_destruct; }; enum kis_ipdata_type { ipdata_unknown = 0, ipdata_factoryguess = 1, ipdata_udptcp = 2, ipdata_arp = 3, ipdata_dhcp = 4, ipdata_group = 5 }; class kis_ip_data { public: kis_ip_data() { ip_type = ipdata_unknown; ip_addr_block.s_addr = 0; ip_netmask.s_addr = 0; ip_gateway.s_addr = 0; } kis_ipdata_type ip_type; in_addr ip_addr_block; in_addr ip_netmask; in_addr ip_gateway; inline kis_ip_data& operator= (const kis_ip_data& in) { ip_addr_block.s_addr = in.ip_addr_block.s_addr; ip_netmask.s_addr = in.ip_netmask.s_addr; ip_gateway.s_addr = in.ip_gateway.s_addr; ip_type = in.ip_type; return *this; } }; class Packinfo_Sig_Combo { public: Packinfo_Sig_Combo(kis_layer1_packinfo *l1, kis_gps_packinfo *gp) { lay1 = l1; gps = gp; } kis_layer1_packinfo *lay1; kis_gps_packinfo *gps; }; // SNR info struct kis_signal_data { kis_signal_data() { // These all go to 0 since we don't know if it'll be positive or // negative last_signal_dbm = last_noise_dbm = 0; min_signal_dbm = min_noise_dbm = 0; max_signal_dbm = max_noise_dbm = -256; last_signal_rssi = last_noise_rssi = 0; min_signal_rssi = min_noise_rssi = 1024; max_signal_rssi = max_noise_rssi = 0; peak_lat = peak_lon = peak_alt = 0; maxseenrate = 0; encodingset = 0; carrierset = 0; } int last_signal_dbm, last_noise_dbm; int min_signal_dbm, min_noise_dbm; int max_signal_dbm, max_noise_dbm; int last_signal_rssi, last_noise_rssi; int min_signal_rssi, min_noise_rssi; int max_signal_rssi, max_noise_rssi; // Peak locations double peak_lat, peak_lon, peak_alt; // Max rate int maxseenrate; // Seen encodings uint32_t encodingset; uint32_t carrierset; inline kis_signal_data& operator= (const kis_signal_data& in) { last_signal_dbm = in.last_signal_dbm; last_noise_dbm = in.last_noise_dbm; min_signal_dbm = in.min_signal_dbm; max_signal_dbm = in.max_signal_dbm; min_noise_dbm = in.min_noise_dbm; max_noise_dbm = in.max_noise_dbm; last_signal_rssi = in.last_signal_rssi; last_noise_rssi = in.last_noise_rssi; min_signal_rssi = in.min_signal_rssi; max_signal_rssi = in.max_signal_rssi; min_noise_rssi = in.min_noise_rssi; max_noise_rssi = in.max_noise_rssi; peak_lat = in.peak_lat; peak_lon = in.peak_lon; peak_alt = in.peak_alt; maxseenrate = in.maxseenrate; encodingset = in.encodingset; carrierset = in.carrierset; return *this; } inline kis_signal_data& operator+= (const Packinfo_Sig_Combo& in) { if (in.lay1 != NULL) { int gpscopy = 0; if (in.lay1->signal_dbm < min_signal_dbm && in.lay1->signal_dbm != 0) min_signal_dbm = in.lay1->signal_dbm; if (in.lay1->signal_rssi < min_signal_rssi && in.lay1->signal_rssi != 0) min_signal_rssi = in.lay1->signal_rssi; if (in.lay1->signal_dbm > max_signal_dbm && in.lay1->signal_dbm != 0) { max_signal_dbm = in.lay1->signal_dbm; gpscopy = 1; } if (in.lay1->signal_rssi > max_signal_rssi && in.lay1->signal_rssi != 0) { max_signal_rssi = in.lay1->signal_rssi; gpscopy = 1; } if (in.lay1->noise_dbm < min_noise_dbm && in.lay1->noise_dbm != 0) min_noise_dbm = in.lay1->noise_dbm; if (in.lay1->noise_rssi < min_noise_rssi && in.lay1->noise_rssi != 0) min_noise_rssi = in.lay1->noise_rssi; if (in.lay1->noise_dbm > max_noise_dbm && in.lay1->noise_dbm != 0) max_noise_dbm = in.lay1->noise_dbm; if (in.lay1->noise_rssi > max_noise_rssi && in.lay1->noise_rssi != 0) max_noise_rssi = in.lay1->noise_rssi; if (in.lay1->signal_rssi != 0) last_signal_rssi = in.lay1->signal_rssi; if (in.lay1->signal_dbm != 0) last_signal_dbm = in.lay1->signal_dbm; if (in.lay1->noise_rssi != 0) last_noise_rssi = in.lay1->noise_rssi; if (in.lay1->noise_dbm != 0) last_noise_dbm = in.lay1->noise_dbm; carrierset |= in.lay1->carrier; encodingset |= in.lay1->encoding; if (in.lay1->datarate > maxseenrate) maxseenrate = in.lay1->datarate; if (gpscopy && in.gps != NULL) { peak_lat = in.gps->lat; peak_lon = in.gps->lon; peak_alt = in.gps->alt; } } return *this; } inline kis_signal_data& operator+= (const kis_signal_data& in) { if (in.min_signal_dbm < min_signal_dbm) min_signal_dbm = in.min_signal_dbm; if (in.min_signal_rssi < min_signal_rssi) min_signal_rssi = in.min_signal_rssi; if (in.max_signal_dbm > max_signal_dbm) { max_signal_dbm = in.max_signal_dbm; peak_lat = in.peak_lat; peak_lon = in.peak_lon; peak_alt = in.peak_alt; } if (in.max_signal_rssi > max_signal_rssi) { max_signal_rssi = in.max_signal_rssi; peak_lat = in.peak_lat; peak_lon = in.peak_lon; peak_alt = in.peak_alt; } if (in.min_noise_dbm < min_noise_dbm) min_noise_dbm = in.min_noise_dbm; if (in.min_noise_rssi < min_noise_rssi) min_noise_rssi = in.min_noise_rssi; if (in.max_noise_dbm > max_noise_dbm) max_noise_dbm = in.max_noise_dbm; if (in.max_noise_rssi > max_noise_rssi) max_noise_rssi = in.max_noise_rssi; encodingset |= in.encodingset; carrierset |= in.carrierset; if (maxseenrate < in.maxseenrate) maxseenrate = in.maxseenrate; return *this; } }; // Fwd ktd class kis_tracked_device; // Common values across all PHY types, as the PHY is capable of filling them in class kis_device_common : public tracker_component { public: kis_tracked_device *device; // Tracked PHY type int phy_type; // Time values time_t first_time; time_t last_time; // Total packets int packets; // Link level packets (mgmt frames, etc) int llc_packets; // PHY level failures on errors int error_packets; // Data and encrypted data int data_packets; int crypt_packets; // Amount of data seen uint64_t datasize; // # of packets since last tick int new_packets; // Logical channel as per PHY type int channel; // Frequency int frequency; // raw freqs seen mapped to # of times seen map freq_mhz_map; // GPS info kis_gps_data gpsdata; // SNR kis_signal_data snrdata; // Alert triggered on this device int alert; // Arbitrary tags associated with this device // Tags are case sensitive map arb_tag_map; // We need to be sent int dirty; kis_device_common() { device = NULL; phy_type = KIS_PHY_UNKNOWN; first_time = last_time = 0; packets = 0; llc_packets = data_packets = crypt_packets = error_packets = 0; datasize = 0; new_packets = 0; channel = 0; frequency = 0; alert = 0; dirty = 0; } }; // Container that holds tracked information & a unique key. Key should be unique // across all PHY types & must be generated in consistent way class kis_tracked_device { public: mac_addr key; int phy_type; vector content_vec; kis_tracked_device() { phy_type = KIS_PHY_UNKNOWN; content_vec.resize(MAX_TRACKER_COMPONENTS, NULL); } ~kis_tracked_device() { for (unsigned int y = 0; y < MAX_TRACKER_COMPONENTS; y++) { tracker_component *tcm = content_vec[y]; if (tcm == NULL) continue; if (tcm->self_destruct) delete tcm; content_vec[y] = NULL; } } inline void insert(const unsigned int index, tracker_component *data) { if (index >= MAX_TRACKER_COMPONENTS) return; content_vec[index] = data; } inline void *fetch(const unsigned int index) { if (index >= MAX_TRACKER_COMPONENTS) return NULL; return content_vec[index]; } inline void erase(const unsigned int index) { if (index >= MAX_TRACKER_COMPONENTS) return; if (content_vec[index] != NULL) { if (content_vec[index]->self_destruct) delete content_vec[index]; content_vec[index] = NULL; } } inline tracker_component *operator[] (const unsigned int& index) const { if (index >= MAX_TRACKER_COMPONENTS) return NULL; return content_vec[index]; } }; // Packinfo references class kis_tracked_device_info : public packet_component { public: kis_tracked_device_info() { self_destruct = 1; devref = NULL; } kis_tracked_device *devref; }; // fwd class Devicetracker; // Handler element for a phy // Registered with Devicetracker // Devicetracker feeds packets to phyhandlers, no need to register with packet // chain on each // Registered phy id is passed from devicetracker // // Subclasses are expected to handle: // Packets from a new PHY (via DLT or packet components) and translate them // into trackable entries in DeviceTracker // Appropriate network sentences to export non-common tracking data for this phy // Logging in plaintext and xml class Kis_Phy_Handler { public: Kis_Phy_Handler() { fprintf(stderr, "fatal oops: kis_phy_handler();\n"); exit(1); } // Create a 'weak' handler which provides enough structure to call CreatePhyHandler Kis_Phy_Handler(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; devicetracker = NULL; phyid = -1; phyname = "NONE"; } virtual Kis_Phy_Handler *CreatePhyHandler(GlobalRegistry *in_globalreg, Devicetracker *in_tracker, int in_phyid) = 0; Kis_Phy_Handler(GlobalRegistry *in_globalreg, Devicetracker *in_tracker, int in_phyid) { globalreg = in_globalreg; phyid = in_phyid; devicetracker = in_tracker; } virtual string FetchPhyName() { return phyname; } virtual int FetchPhyId() { return phyid; } // Packet kick, passed from devicetracker virtual int HandlePacket(kis_packet *in_pack) = 0; // Timer event carried from devicetracker, for sending updated // phy-specific records, etc virtual int TimerKick() = 0; // To do: Logging functions protected: GlobalRegistry *globalreg; Devicetracker *devicetracker; string phyname; int phyid; }; class Devicetracker { public: Devicetracker() { fprintf(stderr, "FATAL OOPS: Kis_Tracker()\n"); exit(0); } Devicetracker(GlobalRegistry *in_globalreg); ~Devicetracker(); // Register a phy handler weak class, used to instantiate the strong class // inside devtracker int RegisterPhyHandler(Kis_Phy_Handler *in_weak_handler); // Register a tracked device component int RegisterDeviceComponent(string in_component); int FetchNumDevices(int in_phy); int FetchNumPackets(int in_phy); int FetchNumDatapackets(int in_phy); int FetchNumCryptpackets(int in_phy); int FetchNumErrorpackets(int in_phy); int FetchNumFilterpackets(int in_phy); int FetchPacketRate(int in_phy); int AddFilter(string in_filter); int AddNetCliFilter(string in_filter); void SetDeviceTag(mac_addr in_device, string in_tag, string in_data, int in_persistent); void ClearDeviceTag(mac_addr in_device, string in_tag); string FetchDeviceTag(mac_addr in_device, string in_tag); // Look for an existing device record kis_tracked_device *FetchDevice(mac_addr in_device); // Make a device record kis_tracked_device *GenerateDevice(mac_addr in_device); // Fetch the internal maps. Touching these is generally Bad. Should // only be used when the chain API is insufficient for something, // like linking in directly for xml/net logging. const map FetchTrackedDevices(); static void Usage(char *argv); // Kick the timer event to update the network clients int TimerKick(); // Send all devices to everyone void BlitDevices(int in_fd); protected: void SaveTags(); GlobalRegistry *globalreg; int next_componentid; map component_str_map; map component_id_map; // Total # of packets int num_packets; int num_errorpackets; int num_filterpackets; int num_packetdelta; // Per-phy #s of packets map phy_packets; map phy_errorpackets; map phy_filterpackets; map phy_packetdelta; // Common device component int devcomp_ref_common; // Timer id for main timer kick int timerid; // Network protocols int proto_ref_commondevice; int proto_ref_trackinfo; int proto_ref_devtag; // Tracked devices map tracked_map; // Vector of tracked devices so we can iterate them quickly vector tracked_vec; // Vector of dirty elements for pushing to clients, better than walking // the map every tick, looking for dirty records vector dirty_device_vec; // Filtering FilterCore *track_filter; // Tag records as a config file ConfigFile *tag_conf; time_t conf_save; // Registered PHY types int next_phy_id; map phy_handler_map; }; #endif kismet-2013-03-R1b/filtercore.h0000664000175000017500000000473112124602454015767 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __FILTERCORE_H__ #define __FILTERCORE_H__ // Core filter functions // // Basic filtering class used as a "smart struct" more than anything. Handle // parsing, comparing, etc. #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_LIBPCRE #include #endif #include "globalregistry.h" #include "messagebus.h" #include "packetchain.h" #include "timetracker.h" #include "kis_netframe.h" class FilterCore { public: #ifdef HAVE_LIBPCRE typedef struct { pcre *re; pcre_extra *study; string filter; } pcre_filter; #endif FilterCore(); FilterCore(GlobalRegistry *in_globalreg); // Add a filter line to a block int AddFilterLine(string filter_str); // Run a set of addresses through the filter. We extract this to the // generic layer here so that we're not necessarily tied to the // packinfo_80211 int RunFilter(mac_addr bssidmac, mac_addr sourcemac, mac_addr destmac); // Run the PCRE filters against the incoming text. This isn't an ifdef since // we'll catch it in the implementation. We don't want to have to ifdef every // filter call. int RunPcreFilter(string in_text); int FetchBSSIDHit() { return bssid_hit; } int FetchSourceHit() { return source_hit; } int FetchDestHit() { return dest_hit; } int FetchHits() { return bssid_hit + source_hit + dest_hit; } int FetchPCREHits(); protected: GlobalRegistry *globalreg; macmap bssid_map; macmap source_map; macmap dest_map; int bssid_invert; int source_invert; int dest_invert; int bssid_hit; int source_hit; int dest_hit; #ifdef HAVE_LIBPCRE vector pcre_vec; int pcre_invert; int pcre_hit; #endif }; #endif kismet-2013-03-R1b/tcpserver.cc0000664000175000017500000002371612124602454016010 0ustar dragorndragorn#include "tcpserver.h" #include "configfile.h" TcpServer::TcpServer() { fprintf(stderr, "*** TcpServer() called with no global registry\n"); } TcpServer::TcpServer(GlobalRegistry *in_globalreg) : NetworkServer(in_globalreg) { globalreg = in_globalreg; // Init stuff sv_valid = 0; sv_configured = 0; serv_fd = 0; max_fd = 0; int_ring_len = SRV_RING_LEN; FD_ZERO(&server_fdset); } TcpServer::~TcpServer() { } // Set up the TCP socket and listening int TcpServer::SetupServer(short int in_port, unsigned int in_maxcli, string in_bindaddr, string in_filterstr) { (void) in_filterstr; port = in_port; maxcli = in_maxcli; bindaddr = in_bindaddr; sv_configured = 1; globalreg->RegisterPollableSubsys(this); return 1; } // Set the length of the rings for new connections void TcpServer::SetRingSize(int in_sz) { int_ring_len = in_sz; } int TcpServer::EnableServer() { if (sv_configured == 0) { _MSG("Attempted to enable unconfigured TCP server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Find local host if (gethostname(hostname, MAXHOSTNAMELEN) < 0) { snprintf(errstr, STATUS_MAX, "TCP server gethostname() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Set up socket stuff memset(&serv_sock, 0, sizeof(serv_sock)); serv_sock.sin_family = AF_INET; if (inet_pton(AF_INET, bindaddr.c_str(), &serv_sock.sin_addr.s_addr) == 0) { serv_sock.sin_addr.s_addr = htonl(INADDR_ANY); } // serv_sock.sin_addr.s_addr = htonl(INADDR_ANY); serv_sock.sin_port = htons(port); if ((serv_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "TCP server socket() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Reuse the addr int i = 2; if (setsockopt(serv_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { snprintf(errstr, STATUS_MAX, "TCP server setsockopt(REUSEADDR) failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Bind the socket if (bind(serv_fd, (struct sockaddr *) &serv_sock, sizeof(serv_sock)) < 0) { snprintf(errstr, STATUS_MAX, "TCP server bind() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Listen for connections if (listen(serv_fd, 5) < 0) { snprintf(errstr, STATUS_MAX, "TCP server listen() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Zero and set the FDs and maxfd FD_ZERO(&server_fdset); if (serv_fd > (int) max_fd) max_fd = serv_fd; // We're valid sv_valid = 1; for (unsigned int ipvi = 0; ipvi < ipfilter_vec.size(); ipvi++) { char *netaddr = strdup(inet_ntoa(ipfilter_vec[ipvi]->network)); char *maskaddr = strdup(inet_ntoa(ipfilter_vec[ipvi]->mask)); free(netaddr); free(maskaddr); } snprintf(errstr, 1024, "Created TCP listener on port %d", FetchPort()); _MSG(errstr, MSGFLAG_INFO); return 1; } void TcpServer::KillConnection(int in_fd) { NetworkServer::KillConnection(in_fd); // Close the fd if (in_fd) close(in_fd); } void TcpServer::Shutdown() { for (map::iterator miter = read_buf_map.begin(); miter != read_buf_map.end(); ++miter) { KillConnection(miter->first); // Reset the iterator since we cascade through the generic // netserver::killconnection which removes the ringbuf and // iterator miter = read_buf_map.begin(); if (miter == read_buf_map.end()) break; } sv_valid = 0; if (serv_fd) close(serv_fd); max_fd = 0; } int TcpServer::FetchClientConnectInfo(int in_clid, void *ret_info) { struct sockaddr_in client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(struct sockaddr_in)); client_len = sizeof(struct sockaddr_in); if (getsockname(in_clid, (struct sockaddr *) &client_addr, &client_len) < 0) { snprintf(errstr, STATUS_MAX, "TCP server unable to get sockname for " "client info: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } memcpy(ret_info, &client_addr, client_len); return 1; } int TcpServer::TcpAccept() { int new_fd; struct sockaddr_in client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(struct sockaddr_in)); client_len = sizeof(struct sockaddr_in); // Socket accept if ((new_fd = accept(serv_fd, (struct sockaddr *) &client_addr, &client_len)) < 0) { snprintf(errstr, STATUS_MAX, "TCP server accept() failed: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Bail right now if we have too many connections if (FetchNumClients() >= (int) maxcli) { snprintf(errstr, STATUS_MAX, "TCP server maximum clients (%d) already " "reached.", maxcli); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); close(new_fd); return -1; } // Set it to nonblocking int save_mode = fcntl(new_fd, F_GETFL, 0); fcntl(new_fd, F_SETFL, save_mode | O_NONBLOCK); if (new_fd > (int) max_fd) max_fd = new_fd; FD_SET(new_fd, &server_fdset); // There should never be overlapping fds and there should never be // remnants of an old person here, so we'll make the connection // lightweight and not do more tree searching. If this ever proves // wrong, we need to reevaluate write_buf_map[new_fd] = new RingBuffer(int_ring_len); read_buf_map[new_fd] = new RingBuffer(int_ring_len); return new_fd; } string TcpServer::GetRemoteAddr(int in_fd) { struct sockaddr_in client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(struct sockaddr_in)); client_len = sizeof(struct sockaddr_in); if (getsockname(in_fd, (struct sockaddr *) &client_addr, &client_len) < 0) { snprintf(errstr, STATUS_MAX, "TCP server unable to get sockname: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return "0.0.0.0"; } return string(inet_ntoa(client_addr.sin_addr)); } int TcpServer::Accept() { // Handle the TCP accept stuff return TcpAccept(); } int TcpServer::ValidateIPFilter(int in_fd) { struct sockaddr_in client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(struct sockaddr_in)); client_len = sizeof(struct sockaddr_in); if (getsockname(in_fd, (struct sockaddr *) &client_addr, &client_len) < 0) { snprintf(errstr, STATUS_MAX, "TCP server unable to get sockname: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // No filtering = valid if (ipfilter_vec.size() == 0) return 1; int legal_ip = 0; for (unsigned int ibvi = 0; ibvi < ipfilter_vec.size(); ibvi++) { if ((client_addr.sin_addr.s_addr & ipfilter_vec[ibvi]->mask.s_addr) == ipfilter_vec[ibvi]->network.s_addr) { legal_ip = 1; break; } } if (legal_ip == 0) { snprintf(errstr, STATUS_MAX, "TCP server client from untrusted host " "%s refused", GetRemoteAddr(in_fd).c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(in_fd); return -1; } return 1; } int TcpServer::Validate(int in_fd) { // Just validate based on IP block return ValidateIPFilter(in_fd); } int TcpServer::ReadBytes(int in_fd) { uint8_t recv_bytes[1024]; int ret; if ((ret = read(in_fd, recv_bytes, 1024)) < 0) { if (errno == EINTR || errno == EAGAIN) return 0; snprintf(errstr, STATUS_MAX, "TCP server client read() error for %s: %s", GetRemoteAddr(in_fd).c_str(), strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } if (ret <= 0) { snprintf(errstr, STATUS_MAX, "TCP server client read() ended for %s", GetRemoteAddr(in_fd).c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } if (read_buf_map[in_fd]->InsertData(recv_bytes, ret) == 0) { snprintf(errstr, STATUS_MAX, "TCP server client %s read error, ring " "buffer full", GetRemoteAddr(in_fd).c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } return ret; } int TcpServer::WriteBytes(int in_fd) { uint8_t dptr[1024]; int dlen, ret; // This can't get called on invalid fds, so save some time and // don't check write_buf_map[in_fd]->FetchPtr(dptr, 1024, &dlen); if ((ret = write(in_fd, dptr, dlen)) <= 0) { if (errno == EINTR || errno == EAGAIN) return 0; snprintf(errstr, STATUS_MAX, "TCP server: Killing client %s, write " "error %s", GetRemoteAddr(in_fd).c_str(), strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(in_fd); return -1; } write_buf_map[in_fd]->MarkRead(ret); if (srvframework->BufferDrained(in_fd) < 0) { snprintf(errstr, STATUS_MAX, "TCP server: Error occured calling framework " "buffer drain notification on client %s", GetRemoteAddr(in_fd).c_str()); _MSG(errstr, MSGFLAG_ERROR); KillConnection(in_fd); return -1; } return ret; } kismet-2013-03-R1b/kis_panel_windows.h0000664000175000017500000003263612124602454017355 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_WINDOWS_H__ #define __KIS_PANEL_WINDOWS_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "globalregistry.h" #include "kis_clinetframe.h" #include "kis_panel_widgets.h" #include "kis_panel_network.h" #include "kis_panel_plugin.h" class KisPanelInterface; // Callback for the frontend to pick a server #define KPI_SL_CB_PARMS GlobalRegistry *globalreg, KisPanelInterface *kpi, \ KisNetClient *picked, void *auxptr typedef void (*kpi_sl_cb_hook)(KPI_SL_CB_PARMS); class Kis_Main_Panel : public Kis_Panel { public: Kis_Main_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Main_Panel() called w/out globalreg\n"); exit(1); } Kis_Main_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_Main_Panel(); // separate function for post-add startups so that we exist in the panel // vect and we can make new windows properly virtual void Startup(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); // Passthrough to the display group virtual Kis_Display_NetGroup *FetchSelectedNetgroup(); virtual vector *FetchDisplayNetgroupVector(); virtual Kis_Netlist *FetchDisplayNetlist() { return netlist; } // Add a plugin to the plugin menu virtual int AddPluginMenuItem(string in_name, int (*callback)(void *), void *auxptr); // Toggle check (mostly unused, plugins should add to the main menus now) virtual void SetPluginMenuItemChecked(int in_mi, int in_checked) { menu->SetMenuItemChecked(in_mi, in_checked); } // Add a divider to the View menu to add plugin view options (should be // called by every plugin, will only add the separator once) virtual void AddViewSeparator(); // Similarly add a divider to the Sort menu to add plugin view options virtual void AddSortSeparator(); // Passthroughs to the plugin-relevant packing boxes used to build the UI // Network box (contains network and gps-line) Kis_Panel_Packbox *FetchNetBox() { return netbox; } // Fetch info box (contains network totals, time, etc) Kis_Panel_Packbox *FetchInfoBox() { return optbox; } // Fetch gps line box (contains gps, battery, etc) Kis_Panel_Packbox *FetchLineBox() { return linebox; } // Passthrough to color handling void AddColorPref(string in_pref, string in_txt); // Load sound prefrences from config file void LoadAudioPrefs(); // Speak a keyed string (ugly way to do it but there's no other quick way // and speech happens so rarely it's not worth doing an integer lookup // table for the speech keys) void SpeakString(string type, vector text); struct plugin_menu_opt { int menuitem; int (*callback)(void *); void *auxptr; }; struct colorpref { string pref; string text; }; void MenuAction(int opt); // Network protocol handlers for INFO for the packet graph void NetClientConfigure(KisNetClient *in_cli, int in_recon); void NetClientAdd(KisNetClient *in_cli, int add); void Proto_INFO(CLIPROTO_CB_PARMS); void Proto_GPS(CLIPROTO_CB_PARMS); void Proto_BATTERY(CLIPROTO_CB_PARMS); void Proto_ALERT(CLIPROTO_CB_PARMS); protected: int mn_file, mi_startserver, mi_serverconsole, mi_connect, mi_disconnect, mi_addcard, mi_conf, mi_quit; int mn_plugins, mi_addplugin, mi_noplugins; int mn_preferences, mi_startprefs, mi_serverprefs, mi_colorprefs, mi_netcolprefs, mi_netextraprefs, mi_clicolprefs, mi_cliextraprefs, mi_infoprefs, mi_gpsprefs, mi_audioprefs, mi_warnprefs; int mn_sort, mi_sort_auto, mi_sort_type, mi_sort_chan, mi_sort_crypt, mi_sort_first, mi_sort_first_d, mi_sort_last, mi_sort_last_d, mi_sort_bssid, mi_sort_ssid, mi_sort_packets, mi_sort_packets_d, mi_sort_sdbm; int mn_sort_appended; int mn_view, mi_shownetworks, mi_showclients, mi_showsummary, mi_showstatus, mi_showgps, mi_showbattery, mi_showpps, mi_showsources; int mn_view_appended; int mn_windows, mi_netdetails, mi_addnote, mi_clientlist, mi_chandetails, mi_gps, mi_alerts; int connect_enable; int sortmode; KisStatusText_Messageclient *statuscli; Kis_Status_Text *statustext; Kis_Netlist *netlist; Kis_Clientlist *clientlist; Kis_Info_Bits *infobits; Kis_Free_Text *sourceinfo, *gpsinfo, *batteryinfo; Kis_Panel_Packbox *netbox, *optbox, *linebox, *hbox, *vbox; vector plugin_menu_vec; virtual void UpdateSortMenu(); virtual void UpdateViewMenu(int mi); virtual void SpawnColorPrefs(); virtual void SpawnServerPrefs(); virtual void SpawnInfoPrefs(); vector color_pref_vec; Kis_IntGraph *packetrate; vector pps, datapps; int lastpackets, lastdata; int addref; string agg_gps_fields; int agg_gps_num; // Sound options int snd_new, snd_packet, snd_gpslock, snd_gpslost, snd_alert; string sound_prefix; string spk_new, spk_alert, spk_gpslost, spk_gpslock; }; #define KIS_PROMPT_CB_PARMS GlobalRegistry *globalreg, int ok, int check, void *auxptr typedef void (*ksp_prompt_cb)(KIS_PROMPT_CB_PARMS); class Kis_Prompt_Panel : public Kis_Panel { public: Kis_Prompt_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Prompt_Panel called w/out globalreg\n"); exit(1); } Kis_Prompt_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Prompt_Panel(); void SetDefaultButton(int in_ok); void SetButtonText(string in_oktext, string in_notext); void SetCheckText(string in_text1); void SetChecked(int in_checked); void SetCallback(ksp_prompt_cb in_callback, void *in_auxptr); void SetDisplayText(vector in_text); void ButtonAction(Kis_Panel_Component *component); protected: void *auxptr; ksp_prompt_cb callback; Kis_Free_Text *ftext; Kis_Button *okbutton, *cancelbutton; Kis_Checkbox *check; Kis_Panel_Packbox *vbox, *bbox; }; class Kis_Connect_Panel : public Kis_Panel { public: Kis_Connect_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Connect_Panel called w/out globalreg\n"); exit(1); } Kis_Connect_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Connect_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); void ButtonAction(Kis_Panel_Component *component); protected: Kis_Single_Input *hostname; Kis_Single_Input *hostport; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; }; class Kis_Spawn_Panel : public Kis_Panel { public: Kis_Spawn_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Spawn_Panel called w/out globalreg\n"); exit(1); } Kis_Spawn_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Spawn_Panel(); void ButtonAction(Kis_Panel_Component *component); void SpawnConsole(int in_console) { spawn_console = in_console; } protected: Kis_Single_Input *options, *logname; Kis_Checkbox *logging_check, *console_check; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; int spawn_console; }; class Kis_Console_Panel : public Kis_Panel { public: Kis_Console_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Consol_Panel called w/out globalreg\n"); exit(1); } Kis_Console_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Console_Panel(); void ButtonAction(Kis_Panel_Component *component); void AddConsoleText(string in_text); protected: Kis_Free_Text *constext; Kis_Button *okbutton, *killbutton; Kis_Panel_Packbox *vbox, *bbox; int textcb; }; class Kis_AddCard_Panel : public Kis_Panel { public: Kis_AddCard_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AddCard_Panel called w/out globalreg\n"); exit(1); } Kis_AddCard_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_AddCard_Panel(); virtual void DrawPanel(); void ButtonAction(Kis_Panel_Component *in_button); protected: KisNetClient *target_cli; Kis_Single_Input *srcopts; Kis_Single_Input *srciface; Kis_Single_Input *srcname; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; }; // AddCard callback to trigger building the window void sp_addcard_cb(KPI_SL_CB_PARMS); class Kis_CardList_Panel : public Kis_Panel { public: Kis_CardList_Panel() { fprintf(stderr, "FATAL OOPS: Kis_CardList_Panel called w/out globalreg\n"); exit(1); } Kis_CardList_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_CardList_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); protected: Kis_Scrollable_Table *cardlist; }; class Kis_Plugin_Picker : public Kis_Panel { // Plugin picker lists .so files in the plugin director(ies) and lets // the user pick one to load. public: Kis_Plugin_Picker() { fprintf(stderr, "FATAL OOPS: Kis_Plugin_Picker called w/out globalreg\n"); exit(1); } Kis_Plugin_Picker(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_Plugin_Picker(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void Proto_PLUGIN(CLIPROTO_CB_PARMS); virtual void Proto_PLUGIN_complete(); protected: Kis_Scrollable_Table *pluglist; Kis_Scrollable_Table *spluglist; Kis_Free_Text *helptext, *shelptext; Kis_Button *okbutton; Kis_Panel_Packbox *vbox, *bbox; int net_plugin_ref; int srv_plugin_info; vector *plugins; }; class Kis_Chanconf_Panel : public Kis_Panel { public: Kis_Chanconf_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Chanconf_Panel called w/out globalreg\n"); exit(1); } Kis_Chanconf_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Chanconf_Panel(); virtual void DrawPanel(); void ButtonAction(Kis_Panel_Component *component); protected: Kis_Scrollable_Table *cardlist; Kis_Single_Input *inpchannel, *inprate; Kis_Radiobutton *lockrad, *hoprad, *dwellrad; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox, *cbox; int last_selected, radio_changed; Kis_Radiobutton *last_radio; }; class Kis_Gps_Panel : public Kis_Panel { public: Kis_Gps_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Gps_Panel called w/out globalreg\n"); exit(1); } Kis_Gps_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Gps_Panel(); void ButtonAction(Kis_Panel_Component *component); void Proto_GPS(CLIPROTO_CB_PARMS); protected: Kis_IntGraph *gpssiggraph; // Kis_PolarGraph *gpspolgraph; Kis_Free_Text *gpslocinfo, *gpsmoveinfo, *gpssatinfo; Kis_Button *okbutton; Kis_Panel_Packbox *vbox; //, *tbox, *hbox; vector sat_info_vec; vector sat_label_vec; string agg_gps_fields; int agg_gps_num; int addref; }; class Kis_Clientlist_Panel : public Kis_Panel { public: Kis_Clientlist_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Clientlist_Panel called w/out globalreg\n"); exit(1); } Kis_Clientlist_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Clientlist_Panel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); virtual int GraphTimer(); virtual void DrawPanel(); protected: virtual void UpdateViewMenu(int mi); virtual void UpdateSortMenu(); Kis_Panel_Packbox *vbox; Kis_Clientlist *clientlist; Kis_Free_Text *nettitle; int mn_clients, mi_nextnet, mi_prevnet, mi_close; int mn_preferences, mi_clicolprefs, mi_cliextraprefs; int mn_sort, mi_sort_auto, mi_sort_type, mi_sort_first, mi_sort_first_d, mi_sort_last, mi_sort_last_d, mi_sort_mac, mi_sort_packets, mi_sort_packets_d, mi_sort_sdbm; int mn_view, mi_addnote, mi_details; int grapheventid; }; class Kis_AddNetNote_Panel : public Kis_Panel { public: Kis_AddNetNote_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AddNetNote_Panel()\n"); exit(1); } Kis_AddNetNote_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_AddNetNote_Panel(); virtual void DrawPanel(); virtual void Action(Kis_Panel_Component *in_button, int in_state); protected: Kis_Panel_Packbox *vbox, *bbox; Kis_Single_Input *notetxt; Kis_Checkbox *permanent; Kis_Button *cancelbutton, *okbutton, *delbutton; Kis_Display_NetGroup *dng; mac_addr bssid; }; class Kis_AddCliNote_Panel : public Kis_Panel { public: Kis_AddCliNote_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AddCliNote_Panel()\n"); exit(1); } Kis_AddCliNote_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_AddCliNote_Panel(); virtual void SetClient(Netracker::tracked_client *in_cli); virtual void DrawPanel(); virtual void Action(Kis_Panel_Component *in_button, int in_state); protected: Kis_Panel_Packbox *vbox, *bbox; Kis_Single_Input *notetxt; Kis_Checkbox *permanent; Kis_Button *cancelbutton, *okbutton, *delbutton; Netracker::tracked_client *cli; }; #endif #endif kismet-2013-03-R1b/gpsdclient.h0000664000175000017500000000375712124602454015774 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __GPSDCLIENT_H__ #define __GPSDCLIENT_H__ #include "config.h" #ifndef HAVE_LIBGPS #include "clinetframework.h" #include "tcpclient.h" #include "kis_netframe.h" #include "packetchain.h" #include "gpscore.h" // Our command const char gpsd_init_command[] = "L\n"; // compensate for gpsd ignoring multi-line commands too soon after // eachother const char gpsd_watch_command[] = "J=1,W=1,R=1\n"; const char gpsd_poll_command[] = "PAVM\n"; class GPSDClient : public GPSCore { public: GPSDClient(); GPSDClient(GlobalRegistry *in_globalreg); virtual ~GPSDClient(); virtual int Timer(); // Hooks so we can override straight to the TCP core virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set& in_rset, fd_set& in_wset) { return netclient->Poll(in_rset, in_wset); } virtual int ParseData(); virtual int Shutdown(); virtual int Reconnect(); virtual void ConnectCB(int status); protected: TcpClient *tcpcli; char host[MAXHOSTNAMELEN]; int port; int last_mode; int poll_mode; int si_units, si_raw; time_t last_hed_time; time_t last_update; time_t last_tpv; }; #endif #endif kismet-2013-03-R1b/packetsource_wext.h0000664000175000017500000001346612124602454017375 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * WEXT is the linux wireless extensions tools subset of pcap capture devices. * Anything controlled by the standard wireless extensions will live here. */ #ifndef __PACKETSOURCE_WEXT_H__ #define __PACKETSOURCE_WEXT_H__ #include "config.h" #if (defined(HAVE_LIBPCAP) && defined(SYS_LINUX) && defined(HAVE_LINUX_WIRELESS)) #include #include #include #include #include #include #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #include "ifcontrol.h" #include "iwcontrol.h" #ifdef HAVE_LINUX_SYS_RADIOTAP #include #endif #ifdef HAVE_LOCALRADIOTAP #include "local_ieee80211_radiotap.h" #endif #define USE_PACKETSOURCE_WEXT #define USE_PACKETSOURCE_MADWIFI #define USE_PACKETSOURCE_WRT54PRISM // Another tier of subclassing. In some respects this is sort of silly, but it's // fairly logical as far as progression of functionality goes. // // Wext is both an actual class and a virtual layer. Some wext code needs // special hooks for monitor, channel, etc, and can subclass this. Otherwise, // Wext handles it internally w/ the standard commands class PacketSource_Wext : public PacketSource_Pcap { public: PacketSource_Wext() { fprintf(stderr, "FATAL OOPS: Packetsource_Wext() called\n"); exit(1); } PacketSource_Wext(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Wext(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Wext(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Wext(); virtual int ParseOptions(vector *in_opts); // Should be, something can override if it needs virtual int FetchChannelCapable() { return 1; } virtual int OpenSource(); // Generic-level functions virtual int EnableMonitor(); virtual int DisableMonitor(); virtual int SetChannel(unsigned int in_ch); virtual int FetchHardwareChannel(); virtual vector FetchSupportedChannels(string in_interface); virtual int ScanWpaSupplicant(); protected: // Stuff we need to track to restore later struct linux_ifparm { short flags; char essid[MAX_SSID_LEN + 1]; int channel; int mode; int privmode; int prismhdr; }; int stored_flags; string stored_essid; int stored_channel; int stored_mode; int stored_privmode; string vap, parent; int use_mac80211, opp_vap, force_vap; vector mac80211_flag_vec; void *nlcache, *nlfamily; bool ignore_primary_state; virtual void FetchRadioData(kis_packet *in_packet); virtual void OpenWpaSupplicant(); int scan_wpa; int wpa_sock; string wpa_path; string wpa_local_path; struct sockaddr_un wpa_local, wpa_dest; int wpa_timer_id; }; // Madwifi subclass // Implements local detection of the subtype (madwifi_a, madwifi_bg, etc) class PacketSource_Madwifi : public PacketSource_Wext { public: PacketSource_Madwifi() { fprintf(stderr, "FATAL OOPS: Packetsource_Madwifi() called\n"); exit(1); } PacketSource_Madwifi(GlobalRegistry *in_globalreg) : PacketSource_Wext(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Madwifi(in_globalreg, in_interface, in_opts); } virtual int OpenSource(); virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Madwifi(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Madwifi() { } virtual int EnableMonitor(); virtual int DisableMonitor(); protected: // 1 - madwifi_a // 2 - madwifi_b // 3 - madwifi_g // 0 - madwifi_ag int madwifi_type; int vapdestroy; int driver_ng; int shutdowndestroy; string parent; }; // Wrt54prism subclass // Implements the wrt54prism source for openwrt class PacketSource_Wrt54Prism : public PacketSource_Wext { public: // HANDLED PACKET SOURCES: // wrt54prism PacketSource_Wrt54Prism() { fprintf(stderr, "FATAL OOPS: Packetsource_Wrt54prism() called\n"); exit(1); } PacketSource_Wrt54Prism(GlobalRegistry *in_globalreg) : PacketSource_Wext(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Wrt54Prism(in_globalreg, in_interface, in_opts); } // We don't do autotype scanning virtual int AutotypeProbe(string in_device) { return 0; } virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Wrt54Prism(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Wrt54Prism() { } virtual int OpenSource(); }; #endif /* have_libpcap && sys_linux */ #endif kismet-2013-03-R1b/restricted-plugin-autowep/0000775000175000017500000000000012124602454020601 5ustar dragorndragornkismet-2013-03-R1b/restricted-plugin-autowep/Makefile0000664000175000017500000000155512124602454022247 0ustar dragorndragorn# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC PLUGOBJS = autowep-kismet.o PLUGOUT = autowep-kismet.so all: $(PLUGOUT) $(PLUGOUT): $(PLUGOBJS) $(LD) $(PLUGINLDFLAGS) $(PLUGOBJS) -o $(PLUGOUT) $(LIBS) install: $(PLUGOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $^ $(DESTDIR)/$(plugindir)/$^ userinstall: $(PLUGOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) $(PLUGOUT) ${HOME}/.kismet/plugins/$(PLUGOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/restricted-plugin-autowep/autowep-kismet.cc0000664000175000017500000003053512124602454024074 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GlobalRegistry *globalreg = NULL; mac_addr fios_macs[] = { mac_addr("00:18:01:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:1F:90:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:0F:B3:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:15:05:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:1B:03:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:1E:A7:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:20:E0:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:24:7B:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:26:62:00:00:00/FF:FF:FF:00:00:00"), mac_addr("00:26:B8:00:00:00/FF:FF:FF:00:00:00") }; #define num_fios_macs 10 struct kisautowep_net { mac_addr bssid; unsigned int ssid_valid; unsigned int key_confirmed; unsigned int key_failed; unsigned char key[5]; Netracker::tracked_network *net; }; struct kisautowep_state { map netmap; int alert_ref; unsigned char wep_identity[256]; }; kisautowep_state *state; kisautowep_net *kisautowep_new() { kisautowep_net *net = new kisautowep_net; net->ssid_valid = 0; net->key_confirmed = 0; net->key_failed = 0; net->net = NULL; return net; } // Sort all the lowest-effort stuff to the top of the pile, exclude // packets based on wrong phy, wrong OUI, missing tracking data, before // doing local map searches int kisautowep_packet_hook(CHAINCALL_PARMS) { kisautowep_state *kstate = (kisautowep_state *) auxdata; kisautowep_net *anet = NULL; char keystr[11]; // printf("debug - autoweb packet hook\n"); // Pull the dot11 decode kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); if (packinfo == NULL) { return 0; } // Not an 802.11 frame type we known how to track, we'll just skip // it, too if (packinfo->corrupt || packinfo->type == packet_noise || packinfo->type == packet_unknown || packinfo->subtype == packet_sub_unknown) { return 0; } // We have to have a network record Netracker::tracked_network *net; kis_netracker_netinfo *netpackinfo = (kis_netracker_netinfo *) in_pack->fetch(_PCM(PACK_COMP_TRACKERNET)); // No network? Can't handle this either. if (netpackinfo == NULL) { return 0; } // We can only make new networks on beacons if (packinfo->type != packet_management || packinfo->subtype != packet_sub_beacon) return 0; net = netpackinfo->netref; // Has to have exactly 1 ssid, since no default ap is going to be doing // anything clever if (net->ssid_map.size() < 1) return 0; // If we already know about it, we only care about data frames map::iterator nmi; if ((nmi = kstate->netmap.find(net->bssid)) != kstate->netmap.end()) { return 0; } int bssid_possible = 0; // is it a fios AP? for (unsigned int x = 0; x < num_fios_macs; x++) { if (net->bssid == fios_macs[x]) { bssid_possible = 1; break; } } // Dump out if we're not the right OUI if (bssid_possible == 0) return 0; // Get the SSID in the stupidest way possible (we know it's only 1...) Netracker::adv_ssid_data *ssid = ((net->ssid_map.begin())++)->second; // We need to make a net anet = kisautowep_new(); anet->bssid = net->bssid; anet->net = net; // Remember it kstate->netmap[net->bssid] = anet; // Has to be AP if (ssid->type != ssid_beacon) return 0; // Has to be WEP if (ssid->cryptset != crypt_wep) return 0; // Has to be 5 characters if (ssid->ssid.length() != 5) { return 0; } // Has to be 0-9 A-Z for (unsigned int x = 0; x < ssid->ssid.length(); x++) { if ((ssid->ssid[x] < '0' || ssid->ssid[x] > '9') && (ssid->ssid[x] < 'A' || ssid->ssid[x] > 'Z')) { return 0; } } // Plausible ssid anet->ssid_valid = 1; // Calculate the base36 value unsigned long int base36 = 0; for (unsigned int x = 0; x < ssid->ssid.length(); x++) { if (ssid->ssid[x] >= '0' && ssid->ssid[x] <= '9') { base36 += (ssid->ssid[x] - '0') * pow(36, x); } else if (ssid->ssid[x] >= 'A' && ssid->ssid[x] <= 'Z') { base36 += (ssid->ssid[x] - 'A' + 10) * pow(36, x); } } // First 2 bits, bytes 1 and 2 of the BSSID anet->key[0] = net->bssid[1]; anet->key[1] = net->bssid[2]; for (unsigned int x = 0; x < 3; x++) { // TODO - this probably doesn't work on little endian? anet->key[4 - x] = (base36 >> (x * 8)) & 0xFF; } snprintf(keystr, 11, "%02X%02X%02X%02X%02X", anet->key[0], anet->key[1], anet->key[2], anet->key[3], anet->key[4]); string al = "Auto-WEP guessed default WEP key " + string(keystr) + " for network '" + MungeToPrintable(ssid->ssid) + "' BSSID " + net->bssid.Mac2String(); _MSG(al, MSGFLAG_INFO); globalreg->netracker->SetNetworkTag(net->bssid, "WEP-AUTO-LIKELY", string(keystr), 0); return 0; } // Handle data frames before classification int kisautowep_data_hook(CHAINCALL_PARMS) { kisautowep_state *kstate = (kisautowep_state *) auxdata; kisautowep_net *anet = NULL; char keystr[11]; // Pull the dot11 decode kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); if (packinfo == NULL) { return 0; } // Not an 802.11 frame type we known how to track, we'll just skip // it, too if (packinfo->corrupt || packinfo->type == packet_noise || packinfo->type == packet_unknown || packinfo->subtype == packet_sub_unknown) { return 0; } // We don't care about anything but data if we've already seen the network if (packinfo->type != packet_data || packinfo->decrypted) { return 0; } map::iterator nmi; // Don't do anything if we don't know what this is if ((nmi = kstate->netmap.find(packinfo->bssid_mac)) == kstate->netmap.end()) return 0; // Get the SSID in the stupidest way possible (we know it's only 1...) Netracker::adv_ssid_data *ssid = ((nmi->second->net->ssid_map.begin())++)->second; // If we've confirmed everything, we're done if (nmi->second->key_confirmed) { return 0; } // If we're not a valid network, don't try if (nmi->second->ssid_valid == 0) { return 0; } // If we've tried too much, we give up if (nmi->second->key_failed > 5) { return 0; } kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } if (chunk == NULL) { return 0; } kis_datachunk *decrypted; snprintf(keystr, 11, "%02X%02X%02X%02X%02X", nmi->second->key[0], nmi->second->key[1], nmi->second->key[2], nmi->second->key[3], nmi->second->key[4]); decrypted = KisBuiltinDissector::DecryptWEP(packinfo, chunk, nmi->second->key, 5, kstate->wep_identity); // If we couldn't decrypt, we failed if (decrypted == NULL) { // Brute force the other keys, but only a few times! Otherwise we're // doing 10x decrypts on every packet. We only try the other keys the // first N data packets we see. This is incase the wired mac used // to derive the key is an actiontec OUI but not the same OUI // as the wireless if (nmi->second->key_failed < 5) { unsigned char modkey[5]; memcpy(modkey, nmi->second->key, 5); for (unsigned int x = 0; x < num_fios_macs; x++) { modkey[0] = fios_macs[x][1]; modkey[1] = fios_macs[x][2]; decrypted = KisBuiltinDissector::DecryptWEP(packinfo, chunk, modkey, 5, kstate->wep_identity); if (decrypted != NULL) { memcpy(nmi->second->key, modkey, 5); snprintf(keystr, 11, "%02X%02X%02X%02X%02X", nmi->second->key[0], nmi->second->key[1], nmi->second->key[2], nmi->second->key[3], nmi->second->key[4]); _MSG("Auto-WEP found alternate WEP key " + string(keystr) + " for network '" + MungeToPrintable(ssid->ssid) + "' BSSID " + nmi->second->bssid.Mac2String(), MSGFLAG_INFO); nmi->second->key_failed = 0; globalreg->netracker->ClearNetworkTag(nmi->second->bssid, "WEP-AUTO-FAIL"); goto autowep_key_ok; } } } // First-time-fail ops, set the fail attribute for the key, // remove the likely attribute if (nmi->second->key_failed == 0) { _MSG("Auto-WEP failed to confirm WEP keys for network '" + MungeToPrintable(ssid->ssid) + "' BSSID " + nmi->second->bssid.Mac2String() + " network may not be using " "default WEP", MSGFLAG_INFO); globalreg->netracker->ClearNetworkTag(nmi->second->bssid, "WEP-AUTO-LIKELY"); globalreg->netracker->SetNetworkTag(nmi->second->bssid, "WEP-AUTO-FAIL", "Not using default WEP key", 0); } // Increment fail count nmi->second->key_failed++; return 0; } // I know. Shut up. autowep_key_ok: // printf("debug - %s got to key ok\n", nmi->second->bssid.Mac2String().c_str()); // Otherwise free what we just decrypted free(decrypted); nmi->second->key_confirmed = 1; string al = "Auto-WEP confirmed default WEP key " + string(keystr) + " for network '" + MungeToPrintable(ssid->ssid) + "' BSSID " + nmi->second->bssid.Mac2String(); _MSG(al, MSGFLAG_INFO); // Raise the alert globalreg->alertracker->RaiseAlert(kstate->alert_ref, NULL, nmi->second->bssid, nmi->second->bssid, nmi->second->bssid, nmi->second->bssid, nmi->second->net->channel, al); globalreg->netracker->ClearNetworkTag(nmi->second->bssid, "WEP-AUTO-LIKELY"); globalreg->netracker->ClearNetworkTag(nmi->second->bssid, "WEP-AUTO-FAIL"); globalreg->netracker->SetNetworkTag(nmi->second->bssid, "WEP-AUTO", string(keystr), 1); globalreg->builtindissector->AddWepKey(nmi->second->bssid, nmi->second->key, 5, 1); return 0; } int kisautowep_unregister(GlobalRegistry *in_globalreg) { globalreg->packetchain->RemoveHandler(&kisautowep_packet_hook, CHAINPOS_CLASSIFIER); globalreg->packetchain->RemoveHandler(&kisautowep_data_hook, CHAINPOS_CLASSIFIER); return 0; } int kisautowep_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; state = new kisautowep_state; // Hook after we've classified the network for detecting autowep networks, // since we need the SSID to be associated globalreg->packetchain->RegisterHandler(&kisautowep_packet_hook, state, CHAINPOS_CLASSIFIER, 100); // Register data handler late after the existing LLC handlers so we get all // their state, but before the crypt handlers globalreg->packetchain->RegisterHandler(&kisautowep_data_hook, state, CHAINPOS_LLCDISSECT, 100); state->alert_ref = globalreg->alertracker->RegisterAlert("AUTOWEP", sat_minute, 20, sat_second, 5); for (unsigned int wi = 0; wi < 256; wi++) state->wep_identity[wi] = wi; return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "AUTOWEP"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "AutoWEP Plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = kisautowep_register; data->plugin_unregister = kisautowep_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } kismet-2013-03-R1b/restricted-plugin-autowep/README0000664000175000017500000000353612124602454021470 0ustar dragorndragornKismet-AutoWEP 1. What is Kismet-AutoWEP 2. Compiling 3. Installing 4. Using 1. What is Kismet-AutoWEP Many nationwide carriers have started turning on WEP by default in routers, however in addition to the normal flaws in WEP, the key is easily derived from the BSSID and SSID http://xkyle.com/2009/03/03/verizon-fios-wireless-key-calculator/ explains the algorithm used for one popular carrier. 2. Compiling Compiling the Kismet-AutoWEP plugin requires the Kismet source be installed and configured. By default, Kismet-AutoWEP expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-autowep/ KIS_SRC_DIR=/home/foo/src/kismet make 3. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-autowep KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-autowep make userinstall 4. Using Kismet-AutoWEP is essentially automatic. Once loaded, it will look for APs which match the OUIs of vendors using default algorithmic WEP keys, compare the SSIDs to make sure they match the pattern, and derive the WEP key. A derived key will be added as a network tag (WEP-AUTO-LIKELY), and will be transformed into a permanent tag (WEP-AUTO) once a data packet is received and the keys can be confirmed. An alert is raised (of class "AUTOWEP") when an access point is found to be vulnerable. kismet-2013-03-R1b/statealert.cc0000664000175000017500000000715712124602454016144 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "statealert.h" int bsstsalert_chain_hook(CHAINCALL_PARMS) { return ((BSSTSStateAlert *) auxdata)->ProcessPacket(in_pack); } BSSTSStateAlert::BSSTSStateAlert(GlobalRegistry *in_globalreg) : StateAlert(in_globalreg) { if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: BSSTSStateAlert before packetchain\n"); exit(1); } if (globalreg->alertracker == NULL) { fprintf(stderr, "FATAL OOPS: BSSTSStateAlert before alertracker\n"); exit(1); } // Register the packet chain element globalreg->packetchain->RegisterHandler(&bsstsalert_chain_hook, this, CHAINPOS_CLASSIFIER, -50); // Activate our alert alert_bss_ts_ref = globalreg->alertracker->ActivateConfiguredAlert("BSSTIMESTAMP"); } BSSTSStateAlert::~BSSTSStateAlert() { for (map::iterator x = state_map.begin(); x != state_map.end(); ++x) { delete x->second; } state_map.clear(); } int BSSTSStateAlert::ProcessPacket(kis_packet *in_pack) { // Get the 802.11 data kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); if (packinfo == NULL) return 0; if (packinfo->type != packet_management || packinfo->subtype != packet_sub_beacon || packinfo->distrib == distrib_adhoc) return 0; map::iterator smi = state_map.find(packinfo->bssid_mac); if (smi == state_map.end()) { bss_rec *r = new bss_rec; r->incident = 0; r->bss_timestamp = packinfo->timestamp; r->ts.tv_sec = in_pack->ts.tv_sec; r->ts.tv_usec = in_pack->ts.tv_usec; state_map[packinfo->bssid_mac] = r; return 0; } bss_rec *br = smi->second; struct timeval ts_diff; SubtractTimeval(&(in_pack->ts), &(br->ts), &ts_diff); if (ts_diff.tv_sec > 1 || (ts_diff.tv_sec < 1 && ts_diff.tv_usec > 500000)) { br->bss_timestamp = packinfo->timestamp; br->ts.tv_sec = in_pack->ts.tv_sec; br->ts.tv_usec = in_pack->ts.tv_usec; br->incident = 0; return 1; } if (packinfo->timestamp < br->bss_timestamp && (long int) br->bss_timestamp - (long int) packinfo->timestamp > 500000) { if (br->incident > 0) { // Raise an alert ostringstream oss; oss << "Network BSSID " << packinfo->bssid_mac.Mac2String() << " BSS timestamp fluctuating, which may indicate a spoofed " "network cloning the MAC address (BSSTS " << packinfo->timestamp << " vs " << br->bss_timestamp << ")"; globalreg->alertracker->RaiseAlert(alert_bss_ts_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, oss.str()); br->incident = 0; } else { br->incident += 5; } } else if (br->incident > 0) { br->incident--; } br->bss_timestamp = packinfo->timestamp; br->ts.tv_sec = in_pack->ts.tv_sec; br->ts.tv_usec = in_pack->ts.tv_usec; return 1; } kismet-2013-03-R1b/tcpdump-extract.h0000664000175000017500000001103212124602454016745 0ustar dragorndragorn/* * Copyright (c) 1992, 1993, 1994, 1995, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) $Header: /home/dragorn/src/CVS/kismet/kismet-devel/tcpdump-extract.h,v 1.2 2004/01/26 19:28:48 dragorn Exp $ (LBL) */ /* Network to host order macros */ #ifdef LBL_ALIGN /* * The processor doesn't natively handle unaligned loads. */ #ifdef HAVE___ATTRIBUTE__ /* * We have __attribute__; we assume that means we have __attribute__((packed)). * Declare packed structures containing a u_int16_t and a u_int32_t, * cast the pointer to point to one of those, and fetch through it; * the GCC manual doesn't appear to explicitly say that * __attribute__((packed)) causes the compiler to generate unaligned-safe * code, but it apppears to do so. * * We do this in case the compiler can generate, for this instruction set, * better code to do an unaligned load and pass stuff to "ntohs()" or * "ntohl()" than the code to fetch the bytes one at a time and * assemble them. (That might not be the case on a little-endian platform, * where "ntohs()" and "ntohl()" might not be done inline.) */ typedef struct { u_int16_t val; } __attribute__((__packed__)) unaligned_u_int16_t; typedef struct { u_int32_t val; } __attribute__((__packed__)) unaligned_u_int32_t; #define EXTRACT_16BITS(p) \ ((u_int16_t)ntohs(((const unaligned_u_int16_t *)(p))->val)) #define EXTRACT_32BITS(p) \ ((u_int32_t)ntohl(((const unaligned_u_int32_t *)(p))->val)) #else /* HAVE___ATTRIBUTE__ */ /* * We don't have __attribute__, so do unaligned loads of big-endian * quantities the hard way - fetch the bytes one at a time and * assemble them. */ #define EXTRACT_16BITS(p) \ ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 1))) #define EXTRACT_32BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 3))) #endif /* HAVE___ATTRIBUTE__ */ #else /* LBL_ALIGN */ /* * The processor natively handles unaligned loads, so we can just * cast the pointer and fetch through it. */ #define EXTRACT_16BITS(p) \ ((u_int16_t)ntohs(*(const u_int16_t *)(p))) #define EXTRACT_32BITS(p) \ ((u_int32_t)ntohl(*(const u_int32_t *)(p))) #endif /* LBL_ALIGN */ #define EXTRACT_24BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 2))) /* Little endian protocol host order macros */ #define EXTRACT_LE_8BITS(p) (*(p)) #define EXTRACT_LE_16BITS(p) \ ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 0))) #define EXTRACT_LE_32BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 0))) #define EXTRACT_LE_64BITS(p) \ ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 7) << 56 | \ (u_int64_t)*((const u_int8_t *)(p) + 6) << 48 | \ (u_int64_t)*((const u_int8_t *)(p) + 5) << 40 | \ (u_int64_t)*((const u_int8_t *)(p) + 4) << 32 | \ (u_int64_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int64_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int64_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int64_t)*((const u_int8_t *)(p) + 0))) kismet-2013-03-R1b/packetsource_darwin.cc0000664000175000017500000001446712124602454020032 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(SYS_DARWIN) #include #include #include #include #include #include #include extern "C" { #include "apple80211.h" #include #include "darwin_control_wrapper.h" } #include "packetsource_darwin.h" #include "packetsourcetracker.h" /* Iterate over the IO registry, look for a specific type of card * thanks to Kevin Finisterre */ int darwin_cardcheck(const char *service) { mach_port_t masterPort; io_iterator_t iterator; io_object_t sdev; kern_return_t err; if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS) { return -1; } if (IORegistryCreateIterator(masterPort, kIOServicePlane, kIORegistryIterateRecursively, &iterator) == KERN_SUCCESS) { while ((sdev = IOIteratorNext(iterator))) { if (sdev != MACH_PORT_NULL) { io_name_t thisClassName; io_name_t name; err = IOObjectGetClass(sdev, thisClassName); err = IORegistryEntryGetName(sdev, name); if (IOObjectConformsTo(sdev, service)) { IOObjectRelease(iterator); return 0; } } } IOObjectRelease(iterator); } return 1; } int PacketSource_Darwin::OpenSource() { return PacketSource_Pcap::OpenSource(); } int PacketSource_Darwin::AutotypeProbe(string in_device) { if (in_device.substr(0, 2) == "en" || in_device.substr(0, 3) == "wlt") { type = "darwin"; return 1; } return 0; } int PacketSource_Darwin::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("darwin", this, "IEEE80211b", 0); return 1; } PacketSource_Darwin::PacketSource_Darwin(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { fcsbytes = 4; } int PacketSource_Darwin::EnableMonitor() { char devname[16]; int devnum; char errstr[1024]; if (sscanf(interface.c_str(), "%16[^0-9]%d", devname, &devnum) != 2) { _MSG("OSX Darwin interface could not parse '" + interface + "' " "into wlt# or en#, malformed interface name", MSGFLAG_FATAL); globalreg->fatal_condition = 1; } cherror_pending = 0; control = darwin_allocate_interface(devname); if (darwin_get_corewifi(control)) { _MSG("Darwin source " + name + ": Looks like Snow Leopard (10.6) " "or newer is installed and CoreWireless knew what we were.", MSGFLAG_INFO); } else if (darwin_cardcheck("AirPort_Brcm43xx") == 0 || darwin_cardcheck("AirPortPCI_MM") == 0) { if (darwin_bcom_testmonitor() < 0) { _MSG("Darwin source " + name + ": Looks like a broadcom card running " "under Darwin and does not appear to have monitor mode enabled " "in the kernel. Kismet will attempt to enable monitor in " "5 seconds.", MSGFLAG_INFO); sleep(5); if (darwin_bcom_enablemonitor() < 0) { _MSG("Darwin source " + name + ": Failed to enable monitor mode " "for Darwin Broadcom", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } else { _MSG("Darwin source " + name + ": Looks like a Broadcom card " "running under Darwin and already has monitor mode enabled", MSGFLAG_INFO); } } else if (darwin_cardcheck("AirPort_Athr5424ab") == 0) { _MSG("Darwin source " + name + ": Looks like an Atheros card running " "under Darwin. Monitor mode assumed to be on by default in " "these drivers.", MSGFLAG_INFO); } else { _MSG("Darwin source " + name + ": Didn't look like Broadcom or " "Atheros under Darwin. We'll treat it like an Atheros card and " "hope for the best, however it may not work properly.", MSGFLAG_ERROR); sleep(2); } // Bring the control interface up and promisc snprintf(devname, 16, "en%d", devnum); Ifconfig_Delta_Flags(devname, errstr, (IFF_UP | IFF_PROMISC)); if (Ifconfig_Delta_Flags(devname, errstr, (IFF_UP | IFF_PROMISC)) < 0) { _MSG("Darwin source " + name + ": Failed to set interface " + string(devname) + " Up+Promisc: " + string(errstr), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } /* snprintf(devname, 16, "wlt%d", devnum); interface = string(devname); */ return 1; } int PacketSource_Darwin::DisableMonitor() { darwin_free_interface(control); return PACKSOURCE_UNMONITOR_RET_OKWITHWARN; } vector PacketSource_Darwin::FetchSupportedChannels(string in_interface) { vector ret; int *channels; int nch = darwin_get_channels(in_interface.c_str(), &channels); for (int x = 0; x < nch; x++) { ret.push_back(channels[x]); } free(channels); return ret; } int PacketSource_Darwin::SetChannel(unsigned int in_ch) { char err[1024]; // If we're in pending error state, spin if (cherror_pending) { if (globalreg->timestamp.tv_sec - cherror_pending <= 2) { return 0; } else { cherror_pending = 0; // Set the DLT back to the original pcap_set_datalink(pd, orig_dlt); paused = 0; _MSG("Resuming Darwin source " + name + "...", MSGFLAG_INFO); } } if (darwin_set_channel(in_ch, err, control) < 0) { _MSG("Darwin source " + name + ": Failed to set channel " + IntToString(in_ch) + ": " + string(err), MSGFLAG_ERROR); _MSG("Attempting to reset Darwin source " + name + ", will resume channel " "hopping once reset is complete.", MSGFLAG_ERROR); // Remember the DLT, set us back to 10meg, set our delay time, set us to paused // so that we don't process bogus packets orig_dlt = pcap_datalink(pd); darwin_disassociate(control); pcap_set_datalink(pd, DLT_EN10MB); cherror_pending = globalreg->timestamp.tv_sec; paused = 1; } return 0; } #endif kismet-2013-03-R1b/popenclient.cc0000664000175000017500000001726712124602454016317 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "popenclient.h" PopenClient::PopenClient() { fprintf(stderr, "*** PopenClient() called with no global registry reference\n"); } PopenClient::PopenClient(GlobalRegistry *in_globalreg) : NetworkClient(in_globalreg) { childpid = 0; } PopenClient::~PopenClient() { KillConnection(); } int PopenClient::CheckPidVec() { if (childpid <= 0) return 0; for (unsigned int x = 0; x < globalreg->sigchild_vec.size(); x++) { if (globalreg->sigchild_vec[x].pid == childpid) { // Run a final data parse to get any terminating info if (cliframework != NULL) { ReadBytes(); ReadEBytes(); cliframework->ParseData(); } _MSG("Opened process pid " + IntToString(childpid) + " failed: " + IntToString(globalreg->sigchild_vec[x].status), MSGFLAG_ERROR); KillConnection(); globalreg->sigchild_vec.erase(globalreg->sigchild_vec.begin() + x); return -1; } } return 0; } int PopenClient::Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux) { (void) in_port; if (pipe(ipipe) != 0 || pipe(opipe) != 0 || pipe(epipe) != 0) { _MSG("Unable to create pipe: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } if ((childpid = fork()) < 0) { _MSG("Failed to fork: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } else if (childpid == 0) { usleep(500); vector args = QuoteStrTokenize(in_remotehost, " "); char **eargv; eargv = (char **) malloc(sizeof(char *) * (args.size() + 1)); for (unsigned int x = 0; x < args.size(); x++) { eargv[x] = strdup(args[x].c_str()); } eargv[args.size()] = NULL; dup2(ipipe[0], STDIN_FILENO); dup2(opipe[1], STDOUT_FILENO); dup2(epipe[1], STDERR_FILENO); /* We don't need these copies anymore */ close(ipipe[0]); close(ipipe[1]); close(opipe[0]); close(opipe[1]); close(epipe[0]); close(epipe[1]); execvp(eargv[0], eargv); fprintf(stderr, "Launching '%s' failed: %s\n", eargv[0], strerror(errno)); exit(255); } // write-only pipe close(ipipe[0]); // Read-only pipes close(opipe[1]); close(epipe[1]); // Set them to be nonblocking fcntl(opipe[0], F_SETFL, (fcntl(opipe[0], F_GETFL, 0) | O_NONBLOCK)); fcntl(epipe[0], F_SETFL, (fcntl(opipe[0], F_GETFL, 0) | O_NONBLOCK)); cl_valid = 1; write_buf = new RingBuffer(POPEN_RING_LEN); read_buf = new RingBuffer(POPEN_RING_LEN); // Just put something valid in here cli_fd = ipipe[1]; return 1; } void PopenClient::KillConnection() { if (childpid > 0) { kill(childpid, SIGQUIT); close(ipipe[1]); close(opipe[0]); close(epipe[0]); childpid = 0; } cli_fd = -1; // fprintf(stderr, "debug - popenclient calling networkclient killonnection\n"); NetworkClient::KillConnection(); } void PopenClient::SoftKillConnection() { // Send a soft kill and let it die on it's own, so we can capture the // output if any if (childpid > 0) { kill(childpid, SIGTERM); } } void PopenClient::DetatchConnection() { if (childpid > 0) { close(ipipe[1]); close(opipe[0]); close(epipe[0]); childpid = 0; } cl_valid = 0; } int PopenClient::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { int max; if (CheckPidVec() < 0 || !cl_valid) return in_max_fd; max = in_max_fd; if (max < ipipe[1]) max = ipipe[1]; if (max < opipe[0]) max = opipe[0]; if (max < epipe[0]) max = epipe[0]; // opipe is connected to stdout so we treat it as read, same with epipe FD_SET(opipe[0], out_rset); FD_SET(epipe[0], out_rset); if (write_buf != NULL && write_buf->FetchLen() > 0) { FD_SET(ipipe[1], out_wset); } return max; } int PopenClient::Poll(fd_set& in_rset, fd_set& in_wset) { int ret = 0; if (CheckPidVec() < 0 || !cl_valid) return 0; // Look for stuff to read, opipe and epipe are where we read from if (FD_ISSET(opipe[0], &in_rset)) { // If we failed reading, die. if ((ret = ReadBytes()) < 0) { KillConnection(); return ret; } // If we've got new data, try to parse. if we fail, die. if (ret != 0 && cliframework->ParseData() < 0) { KillConnection(); return -1; } } if (FD_ISSET(epipe[0], &in_rset)) { // If we failed reading, die. if ((ret = ReadEBytes()) < 0) { KillConnection(); return ret; } // If we've got new data, try to parse. If we fail, die. if (ret != 0 && cliframework->ParseData() < 0) { KillConnection(); return -1; } } // Look for stuff to write if (FD_ISSET(ipipe[1], &in_wset)) { // If we can't write data, die. if ((ret = WriteBytes()) < 0) KillConnection(); return ret; } return ret; } int PopenClient::ReadBytes() { if (read_buf == NULL) return 0; uint8_t recv_bytes[1024]; int ret; if ((ret = read(opipe[0], recv_bytes, 1024)) < 0) { if (errno == EINTR || errno == EAGAIN) return 0; snprintf(errstr, 1024, "Popen client read() error: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (ret <= 0) { snprintf(errstr, 1024, "Popen application closed"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } if (read_buf->InsertData(recv_bytes, ret) == 0) { snprintf(errstr, 1024, "Popen client fd read error, ring buffer full"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } return ret; } int PopenClient::ReadEBytes() { if (read_buf == NULL) return 0; uint8_t recv_bytes[1024]; int ret; if ((ret = read(epipe[0], recv_bytes, 1024)) < 0) { if (errno == EINTR || errno == EAGAIN) return 0; snprintf(errstr, 1024, "Popen client read() error: %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (ret == 0) { snprintf(errstr, 1024, "Popen application closed"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (read_buf->InsertData(recv_bytes, ret) == 0) { snprintf(errstr, 1024, "Popen client fd read error, ring buffer full"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } return ret; } int PopenClient::WriteBytes() { if (write_buf == NULL) return 0; uint8_t dptr[1024]; int dlen, ret; write_buf->FetchPtr(dptr, 1024, &dlen); if ((ret = write(ipipe[1], dptr, dlen)) <= 0) { snprintf(errstr, 1024, "Popen client: Killing client write error %s", strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } write_buf->MarkRead(ret); return ret; } kismet-2013-03-R1b/getopt.cc0000664000175000017500000005510112124602454015266 0ustar dragorndragorn/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 Free Software Foundation, Inc. This program 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 2, or (at your option) any later version. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* NOTE!!! AIX requires this to be the first thing in the file. Do not put ANYTHING before it! */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include "config.h" #if !__STDC__ && !defined(const) && IN_GCC #define const #endif /* This tells Alpha OSF/1 not to define a getopt prototype in . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #include #ifdef HAVE_STRING_H # include #else # include #endif /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || ( !defined (__GNU_LIBRARY__) && !defined (HAVE_GETOPT_LONG) ) #include /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ /* #define GETOPT_COMPAT */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = 0; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } static void my_bcopy (const char *from, char *to, int size) { int i; for (i = 0; i < size; i++) to[i] = from[i]; } #endif /* GNU C library. */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (char **argv) { int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); char **temp = (char **) alloca (nonopts_size); /* Interchange the two blocks of data in ARGV. */ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], (optind - last_nonopt) * sizeof (char *)); my_bcopy ((char *) temp, (char *) &argv[first_nonopt + optind - last_nonopt], nonopts_size); /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) { int option_index; optarg = 0; /* Initialize the internal data when the first call is made. Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ if (optind == 0) { first_nonopt = last_nonopt = optind = 1; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (getenv ("POSIXLY_CORRECT") != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; } if (nextchar == NULL || *nextchar == '\0') { if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Now skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) optind++; last_nonopt = optind; } /* Special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Start decoding its characters. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only)) #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ )) { const struct option *p; char *s = nextchar; int exact = 0; int ambig = 0; const struct option *pfound = NULL; int indfound; indfound = 0; /* To silence the compiler. */ while (*s && *s != '=') s++; /* Test all options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, s - nextchar)) { if (s - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), exec_name, argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*s) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = s + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), exec_name, pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), exec_name, argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), exec_name, argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), exec_name, nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), exec_name, argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { #if 0 if (c < 040 || c >= 0177) fprintf (stderr, "%s: unrecognized option, character code 0%o\n", exec_name, c); else fprintf (stderr, "%s: unrecognized option `-%c'\n", exec_name, c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), exec_name, c); #endif } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = 0; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { #if 0 fprintf (stderr, "%s: option `-%c' requires an argument\n", exec_name, c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), exec_name, c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } /* Calls internal getopt function to enable long option names. */ int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind) { return _getopt_internal (argc, argv, shortopts, longopts, longind, 0); } int getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ kismet-2013-03-R1b/util.cc0000664000175000017500000006424512124602454014752 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "util.h" #include #include #include #include #include #include #include #ifdef HAVE_LIBUTIL_H # include #endif /* HAVE_LIBUTIL_H */ #if PF_ARGV_TYPE == PF_ARGV_PSTAT #error "pstat?" #endif #if PF_ARGV_TYPE == PF_ARGV_PSTAT # ifdef HAVE_SYS_PSTAT_H # include # else # undef PF_ARGV_TYPE # define PF_ARGV_TYPE PF_ARGV_WRITEABLE # endif /* HAVE_SYS_PSTAT_H */ #endif /* PF_ARGV_PSTAT */ #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS # ifndef HAVE_SYS_EXEC_H # undef PF_ARGV_TYPE # define PF_ARGV_TYPE PF_ARGV_WRITEABLE # else # include # include # endif /* HAVE_SYS_EXEC_H */ #endif /* PF_ARGV_PSSTRINGS */ // We need this to make uclibc happy since they don't even have rintf... #ifndef rintf #define rintf(x) (float) rint((double) (x)) #endif #include #include // Munge input to shell-safe void MungeToShell(char *in_data, int max) { int i, j; for (i = 0, j = 0; i < max && j < max; i++) { if (in_data[i] == '\0') break; if (isalnum(in_data[i]) || isspace(in_data[i]) || in_data[i] == '=' || in_data[i] == '-' || in_data[i] == '_' || in_data[i] == '.' || in_data[i] == ',') { if (j == i) { j++; } else { in_data[j++] = in_data[i]; } } } in_data[j] = '\0'; } // Quick wrapper to save us time in other code string MungeToShell(string in_data) { char *data = new char[in_data.length() + 1]; string ret; snprintf(data, in_data.length() + 1, "%s", in_data.c_str()); MungeToShell(data, in_data.length() + 1); ret = data; delete[] data; return ret; } // Munge text down to printable characters only. Simpler, cleaner munger than // before (and more blatant when munging) string MungeToPrintable(const char *in_data, int max, int nullterm) { string ret; int i; for (i = 0; i < max; i++) { if ((unsigned char) in_data[i] == 0 && nullterm == 1) return ret; if ((unsigned char) in_data[i] >= 32 && (unsigned char) in_data[i] <= 126) { ret += in_data[i]; } else { ret += '\\'; ret += ((in_data[i] >> 6) & 0x03) + '0'; ret += ((in_data[i] >> 3) & 0x07) + '0'; ret += ((in_data[i] >> 0) & 0x07) + '0'; } } return ret; } string MungeToPrintable(string in_str) { return MungeToPrintable(in_str.c_str(), in_str.length(), 1); } string StrLower(string in_str) { string thestr = in_str; for (unsigned int i = 0; i < thestr.length(); i++) thestr[i] = tolower(thestr[i]); return thestr; } string StrUpper(string in_str) { string thestr = in_str; for (unsigned int i = 0; i < thestr.length(); i++) thestr[i] = toupper(thestr[i]); return thestr; } string StrStrip(string in_str) { string temp; unsigned int start, end; start = 0; end = in_str.length(); if (in_str[0] == '\n') return ""; for (unsigned int x = 0; x < in_str.length(); x++) { if (in_str[x] != ' ' && in_str[x] != '\t') { start = x; break; } } for (unsigned int x = in_str.length(); x > 1; ) { x--; if (in_str[x] != ' ' && in_str[x] != '\t' && in_str[x] != '\n') { end = x; break; } } return in_str.substr(start, end-start+1); } string StrPrintable(string in_str) { string thestr; for (unsigned int i = 0; i < in_str.length(); i++) { if (isprint(in_str[i])) { thestr += in_str[i]; } } return thestr; } int IsBlank(const char *s) { int len, i; if (NULL == s) { return 1; } if (0 == (len = strlen(s))) { return 1; } for (i = 0; i < len; ++i) { if (' ' != s[i]) { return 0; } } return 1; } string AlignString(string in_txt, char in_spacer, int in_align, int in_width) { if (in_align == 1) { // Center -- half, text, chop to fit int sp = (in_width / 2) - (in_txt.length() / 2); string ts = ""; if (sp > 0) { ts = string(sp, in_spacer); } ts += in_txt.substr(0, in_width); return ts; } else if (in_align == 2) { // Right -- width - len, chop to fit int sp = (in_width - in_txt.length()); string ts = ""; if (sp > 0) { ts = string(sp, in_spacer); } ts += in_txt.substr(0, in_width); return ts; } // Left align -- make sure it's not too long return in_txt.substr(0, in_width); } int HexStrToUint8(string in_str, uint8_t *in_buf, int in_buflen) { int decode_pos = 0; int str_pos = 0; while ((unsigned int) str_pos < in_str.length() && decode_pos < in_buflen) { short int tmp; if (in_str[str_pos] == ' ') { str_pos++; continue; } if (sscanf(in_str.substr(str_pos, 2).c_str(), "%2hx", &tmp) != 1) { return -1; } in_buf[decode_pos++] = tmp; str_pos += 2; } return decode_pos; } int XtoI(char x) { if (isxdigit(x)) { if (x <= '9') return x - '0'; return toupper(x) - 'A' + 10; } return -1; } int Hex2UChar(unsigned char *in_hex, unsigned char *in_chr) { memset(in_chr, 0, sizeof(unsigned char) * WEPKEY_MAX); int chrpos = 0; for (unsigned int strpos = 0; strpos < WEPKEYSTR_MAX && chrpos < WEPKEY_MAX; strpos++) { if (in_hex[strpos] == 0) break; if (in_hex[strpos] == ':') strpos++; // Assume we're going to eat the pair here if (isxdigit(in_hex[strpos])) { if (strpos > (WEPKEYSTR_MAX - 2)) return 0; int d1, d2; if ((d1 = XtoI(in_hex[strpos++])) == -1) return 0; if ((d2 = XtoI(in_hex[strpos])) == -1) return 0; in_chr[chrpos++] = (d1 * 16) + d2; } } return(chrpos); } // Complex string tokenizer which understands nested delimiters, such as // "foo","bar","baz,foo",something // and network protocols like // foo bar \001baz foo\001 vector BaseStrTokenize(string in_str, string in_split, string in_quote) { size_t begin = 0; size_t end = 0; vector ret; smart_word_token stok; int special = 0; string val; if (in_str.length() == 0) return ret; for (unsigned int x = 0; x < in_str.length(); x++) { if (in_str.find(in_quote, x) == x) { if (special == 0) { // reset beginning on string if we're in a special block begin = x; special = 1; } else { special = 0; } continue; } if (special == 0 && in_str.find(in_split, x) == x) { stok.begin = begin; stok.end = end; stok.word = val; ret.push_back(stok); val = ""; x += in_split.length() - 1; begin = x; continue; } val += in_str[x]; end = x; } stok.begin = begin; stok.end = end; stok.word = val; ret.push_back(stok); return ret; } // No-frills tokenize with no intelligence about nested delimiters vector StrTokenize(string in_str, string in_split, int return_partial) { size_t begin = 0; size_t end = in_str.find(in_split); vector ret; if (in_str.length() == 0) return ret; while (end != string::npos) { string sub = in_str.substr(begin, end-begin); begin = end+1; end = in_str.find(in_split, begin); ret.push_back(sub); } if (return_partial && begin != in_str.size()) ret.push_back(in_str.substr(begin, in_str.size() - begin)); return ret; } // Collapse into basic tokenizer vector NetStrTokenize(string in_str, string in_split, int return_partial) { return BaseStrTokenize(in_str, in_split, "\001"); } // Collapse into basic tokenizer rewrite vector QuoteStrTokenize(string in_str, string in_split) { vector ret; vector bret; bret = BaseStrTokenize(in_str, in_split, "\""); for (unsigned int b = 0; b < bret.size(); b++) { ret.push_back(bret[b].word); } return ret; } int TokenNullJoin(string *ret_str, const char **in_list) { int ret = 0; while (in_list[ret] != NULL) { (*ret_str) += in_list[ret]; if (in_list[ret + 1] != NULL) (*ret_str) += ","; ret++; } return ret; } // Find an option - just like config files string FetchOpt(string in_key, vector *in_vec) { string lkey = StrLower(in_key); if (in_vec == NULL) return ""; for (unsigned int x = 0; x < in_vec->size(); x++) { if ((*in_vec)[x].opt == lkey) return (*in_vec)[x].val; } return ""; } int FetchOptBoolean(string in_key, vector *in_vec, int dvalue) { string s = FetchOpt(in_key, in_vec); return StringToBool(s, dvalue); } vector FetchOptVec(string in_key, vector *in_vec) { string lkey = StrLower(in_key); vector ret; if (in_vec == NULL) return ret; for (unsigned int x = 0; x < in_vec->size(); x++) { if ((*in_vec)[x].opt == lkey) ret.push_back((*in_vec)[x].val); } return ret; } int StringToOpts(string in_line, string in_sep, vector *in_vec) { vector optv; opt_pair optp; int in_tag = 1, in_quote = 0; optp.quoted = 0; for (unsigned int x = 0; x < in_line.length(); x++) { if (in_tag && in_line[x] != '=') { optp.opt += in_line[x]; continue; } if (in_tag && in_line[x] == '=') { in_tag = 0; continue; } if (in_line[x] == '"') { if (in_quote == 0) { in_quote = 1; optp.quoted = 1; } else { in_quote = 0; } continue; } if (in_quote == 0 && in_line[x] == in_sep[0]) { in_vec->push_back(optp); optp.quoted = 0; optp.opt = ""; optp.val = ""; in_tag = 1; continue; } optp.val += in_line[x]; } in_vec->push_back(optp); return 1; } void AddOptToOpts(string opt, string val, vector *in_vec) { opt_pair optp; optp.opt = StrLower(opt); optp.val = val; in_vec->push_back(optp); } void ReplaceAllOpts(string opt, string val, vector *in_vec) { opt_pair optp; optp.opt = StrLower(opt); optp.val = val; for (unsigned int x = 0; x < in_vec->size(); x++) { if ((*in_vec)[x].val == optp.val) { in_vec->erase(in_vec->begin() + x); x--; continue; } } in_vec->push_back(optp); } vector LineWrap(string in_txt, unsigned int in_hdr_len, unsigned int in_maxlen) { vector ret; size_t pos, prev_pos, start, hdroffset; start = hdroffset = 0; for (pos = prev_pos = in_txt.find(' ', in_hdr_len); pos != string::npos; pos = in_txt.find(' ', pos + 1)) { if ((hdroffset + pos) - start >= in_maxlen) { if (pos - prev_pos > (in_maxlen / 5)) { pos = prev_pos = start + (in_maxlen - hdroffset); } string str(hdroffset, ' '); hdroffset = in_hdr_len; str += in_txt.substr(start, prev_pos - start); ret.push_back(str); start = prev_pos; } prev_pos = pos + 1; } while (in_txt.length() - start > (in_maxlen - hdroffset)) { string str(hdroffset, ' '); hdroffset = in_hdr_len; str += in_txt.substr(start, (prev_pos - start)); ret.push_back(str); start = prev_pos; prev_pos+= (in_maxlen - hdroffset); } string str(hdroffset, ' '); str += in_txt.substr(start, in_txt.length() - start); ret.push_back(str); return ret; } string InLineWrap(string in_txt, unsigned int in_hdr_len, unsigned int in_maxlen) { vector raw = LineWrap(in_txt, in_hdr_len, in_maxlen); string ret; for (unsigned int x = 0; x < raw.size(); x++) { ret += raw[x] + "\n"; } return ret; } string SanitizeXML(string in_str) { // Ghetto-fied XML sanitizer. Add more stuff later if we need to. string ret; for (unsigned int x = 0; x < in_str.length(); x++) { if (in_str[x] == '&') ret += "&"; else if (in_str[x] == '<') ret += "<"; else if (in_str[x] == '>') ret += ">"; else ret += in_str[x]; } return ret; } string SanitizeCSV(string in_str) { string ret; for (unsigned int x = 0; x < in_str.length(); x++) { if (in_str[x] == ';') ret += " "; else ret += in_str[x]; } return ret; } void Float2Pair(float in_float, int16_t *primary, int64_t *mantissa) { *primary = (int) in_float; *mantissa = (long) (1000000 * ((in_float) - *primary)); } float Pair2Float(int16_t primary, int64_t mantissa) { return (double) primary + ((double) mantissa / 1000000); } vector Str2IntVec(string in_text) { vector optlist = StrTokenize(in_text, ","); vector ret; int ch; for (unsigned int x = 0; x < optlist.size(); x++) { if (sscanf(optlist[x].c_str(), "%d", &ch) != 1) { ret.clear(); break; } ret.push_back(ch); } return ret; } int RunSysCmd(char *in_cmd) { return system(in_cmd); } pid_t ExecSysCmd(char *in_cmd) { // Slice it into an array to pass to exec vector cmdvec = StrTokenize(in_cmd, " "); char **cmdarg = new char *[cmdvec.size() + 1]; pid_t retpid; unsigned int x; // Convert it to a pointer array for (x = 0; x < cmdvec.size(); x++) cmdarg[x] = (char *) cmdvec[x].c_str(); cmdarg[x] = NULL; if ((retpid = fork()) == 0) { // Nuke the file descriptors so that they don't blat on // input or output for (unsigned int x = 0; x < 256; x++) close(x); execve(cmdarg[0], cmdarg, NULL); exit(0); } delete[] cmdarg; return retpid; } #ifdef SYS_LINUX int FetchSysLoadAvg(uint8_t *in_avgmaj, uint8_t *in_avgmin) { FILE *lf; short unsigned int tmaj, tmin; if ((lf = fopen("/proc/loadavg", "r")) == NULL) { fclose(lf); return -1; } if (fscanf(lf, "%hu.%hu", &tmaj, &tmin) != 2) { fclose(lf); return -1; } (*in_avgmaj) = tmaj; (*in_avgmin) = tmin; fclose(lf); return 1; } #endif // Convert the beacon interval to # of packets per second unsigned int Ieee80211Interval2NSecs(int in_interval) { double interval_per_sec; interval_per_sec = (double) in_interval * 1024 / 1000000; return (unsigned int) ceil(1.0f / interval_per_sec); } uint32_t Adler32Checksum(const char *buf1, int len) { int i; uint32_t s1, s2; char *buf = (char *)buf1; int CHAR_OFFSET = 0; s1 = s2 = 0; for (i = 0; i < (len-4); i+=4) { s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET; s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET); } for (; i < len; i++) { s1 += (buf[i]+CHAR_OFFSET); s2 += s1; } return (s1 & 0xffff) + (s2 << 16); } int IEEE80211Freq[][2] = { {1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432}, {6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457}, {11, 2462}, {12, 2467}, {13, 2472}, {14, 2484}, // We could do the math here, but what about 4ghz nonsense? // We'll do table lookups for now. {36, 5180}, {37, 5185}, {38, 5190}, {39, 5195}, {40, 5200}, {41, 5205}, {42, 5210}, {43, 5215}, {44, 5220}, {45, 5225}, {46, 5230}, {47, 5235}, {48, 5240}, {52, 5260}, {53, 5265}, {54, 5270}, {55, 5275}, {56, 5280}, {57, 5285}, {58, 5290}, {59, 5295}, {60, 5300}, {64, 5320}, {149, 5745}, {150, 5750}, {152, 5760}, {153, 5765}, {157, 5785}, {160, 5800}, {161, 5805}, {165, 5825}, {0, 0} }; int ChanToFreq(int in_chan) { int x = 0; // 80211b frequencies to channels while (IEEE80211Freq[x][0] != 0) { if (IEEE80211Freq[x][0] == in_chan) { return IEEE80211Freq[x][1]; } x++; } return in_chan; } int FreqToChan(int in_freq) { int x = 0; // 80211b frequencies to channels while (IEEE80211Freq[x][1] != 0) { if (IEEE80211Freq[x][1] == in_freq) { return IEEE80211Freq[x][0]; } x++; } return in_freq; } // Multiplatform method of setting a process title. Lifted from proftpd main.c // * ProFTPD - FTP server daemon // * Copyright (c) 1997, 1998 Public Flood Software // * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu // * Copyright (c) 2001, 2002, 2003 The ProFTPD Project team // // Process title munging is ugly! // Externs to glibc #ifdef HAVE___PROGNAME extern char *__progname, *__progname_full; #endif /* HAVE___PROGNAME */ extern char **environ; // This is not good at all. i should probably rewrite this, but... static char **Argv = NULL; static char *LastArgv = NULL; void init_proc_title(int argc, char *argv[], char *envp[]) { register int i, envpsize; char **p; /* Move the environment so setproctitle can use the space. */ for (i = envpsize = 0; envp[i] != NULL; i++) envpsize += strlen(envp[i]) + 1; if ((p = (char **)malloc((i + 1) * sizeof(char *))) != NULL) { environ = p; // Stupid strncpy because it makes the linker not whine for (i = 0; envp[i] != NULL; i++) if ((environ[i] = (char *) malloc(strlen(envp[i]) + 1)) != NULL) strncpy(environ[i], envp[i], strlen(envp[i]) + 1); environ[i] = NULL; } Argv = argv; for (i = 0; i < argc; i++) if (!i || (LastArgv + 1 == argv[i])) LastArgv = argv[i] + strlen(argv[i]); for (i = 0; envp[i] != NULL; i++) if ((LastArgv + 1) == envp[i]) LastArgv = envp[i] + strlen(envp[i]); #ifdef HAVE___PROGNAME /* Set the __progname and __progname_full variables so glibc and company * don't go nuts. */ __progname = strdup("kismet"); __progname_full = strdup(argv[0]); #endif /* HAVE___PROGNAME */ } void set_proc_title(const char *fmt, ...) { va_list msg; static char statbuf[BUFSIZ]; #ifndef HAVE_SETPROCTITLE #if PF_ARGV_TYPE == PF_ARGV_PSTAT union pstun pst; #endif /* PF_ARGV_PSTAT */ char *p; int i,maxlen = (LastArgv - Argv[0]) - 2; #endif /* HAVE_SETPROCTITLE */ va_start(msg,fmt); memset(statbuf, 0, sizeof(statbuf)); #ifdef HAVE_SETPROCTITLE # if __FreeBSD__ >= 4 && !defined(FREEBSD4_0) && !defined(FREEBSD4_1) /* FreeBSD's setproctitle() automatically prepends the process name. */ vsnprintf(statbuf, sizeof(statbuf), fmt, msg); # else /* FREEBSD4 */ /* Manually append the process name for non-FreeBSD platforms. */ snprintf(statbuf, sizeof(statbuf), "%s: ", Argv[0]); vsnprintf(statbuf + strlen(statbuf), sizeof(statbuf) - strlen(statbuf), fmt, msg); # endif /* FREEBSD4 */ setproctitle("%s", statbuf); #else /* HAVE_SETPROCTITLE */ /* Manually append the process name for non-setproctitle() platforms. */ snprintf(statbuf, sizeof(statbuf), "%s: ", Argv[0]); vsnprintf(statbuf + strlen(statbuf), sizeof(statbuf) - strlen(statbuf), fmt, msg); #endif /* HAVE_SETPROCTITLE */ va_end(msg); #ifdef HAVE_SETPROCTITLE return; #else i = strlen(statbuf); #if PF_ARGV_TYPE == PF_ARGV_NEW /* We can just replace argv[] arguments. Nice and easy. */ Argv[0] = statbuf; Argv[1] = NULL; #endif /* PF_ARGV_NEW */ #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* We can overwrite individual argv[] arguments. Semi-nice. */ snprintf(Argv[0], maxlen, "%s", statbuf); p = &Argv[0][i]; while(p < LastArgv) *p++ = '\0'; Argv[1] = NULL; #endif /* PF_ARGV_WRITEABLE */ #if PF_ARGV_TYPE == PF_ARGV_PSTAT pst.pst_command = statbuf; pstat(PSTAT_SETCMD, pst, i, 0, 0); #endif /* PF_ARGV_PSTAT */ #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS PS_STRINGS->ps_nargvstr = 1; PS_STRINGS->ps_argvstr = statbuf; #endif /* PF_ARGV_PSSTRINGS */ #endif /* HAVE_SETPROCTITLE */ } list<_kis_lex_rec> LexString(string in_line, string& errstr) { list<_kis_lex_rec> ret; int curstate = _kis_lex_none; _kis_lex_rec cpr; string tempstr; char lastc = 0; char c = 0; cpr.type = _kis_lex_none; cpr.data = ""; ret.push_back(cpr); for (size_t pos = 0; pos < in_line.length(); pos++) { lastc = c; c = in_line[pos]; cpr.data = ""; if (curstate == _kis_lex_none) { // Open paren if (c == '(') { cpr.type = _kis_lex_popen; ret.push_back(cpr); continue; } // Close paren if (c == ')') { cpr.type = _kis_lex_pclose; ret.push_back(cpr); continue; } // Negation if (c == '!') { cpr.type = _kis_lex_negate; ret.push_back(cpr); continue; } // delimiter if (c == ',') { cpr.type = _kis_lex_delim; ret.push_back(cpr); continue; } // start a quoted string if (c == '"') { curstate = _kis_lex_quotestring; tempstr = ""; continue; } curstate = _kis_lex_string; tempstr = c; continue; } if (curstate == _kis_lex_quotestring) { // We don't close on an escaped \" if (c == '"' && lastc != '\\') { // Drop out of the string and make the lex stack element curstate = _kis_lex_none; cpr.type = _kis_lex_quotestring; cpr.data = tempstr; ret.push_back(cpr); tempstr = ""; continue; } // Add it to the quoted temp strnig tempstr += c; } if (curstate == _kis_lex_string) { // If we're a special character break out and add the lex stack element // otherwise increase our unquoted string if (c == '(' || c == ')' || c == '!' || c == '"' || c == ',') { cpr.type = _kis_lex_string; cpr.data = tempstr; ret.push_back(cpr); tempstr = ""; curstate = _kis_lex_none; pos--; continue; } tempstr += c; continue; } } if (curstate == _kis_lex_quotestring) { errstr = "Unfinished quoted string in line '" + in_line + "'"; ret.clear(); } return ret; } // Taken from the BBN USRP 802.11 encoding code unsigned int update_crc32_80211(unsigned int crc, const unsigned char *data, int len, unsigned int poly) { int i, j; unsigned short ch; for ( i = 0; i < len; ++i) { ch = data[i]; for (j = 0; j < 8; ++j) { if ((crc ^ ch) & 0x0001) { crc = (crc >> 1) ^ poly; } else { crc = (crc >> 1); } ch >>= 1; } } return crc; } void crc32_init_table_80211(unsigned int *crc32_table) { int i; unsigned char c; for (i = 0; i < 256; ++i) { c = (unsigned char) i; crc32_table[i] = update_crc32_80211(0, &c, 1, IEEE_802_3_CRC32_POLY); } } unsigned int crc32_le_80211(unsigned int *crc32_table, const unsigned char *buf, int len) { int i; unsigned int crc = 0xFFFFFFFF; for (i = 0; i < len; ++i) { crc = (crc >> 8) ^ crc32_table[(crc ^ buf[i]) & 0xFF]; } crc ^= 0xFFFFFFFF; return crc; } void SubtractTimeval(struct timeval *in_tv1, struct timeval *in_tv2, struct timeval *out_tv) { if (in_tv1->tv_sec < in_tv2->tv_sec || (in_tv1->tv_sec == in_tv2->tv_sec && in_tv1->tv_usec < in_tv2->tv_usec) || in_tv1->tv_sec == 0 || in_tv2->tv_sec == 0) { out_tv->tv_sec = 0; out_tv->tv_usec = 0; return; } if (in_tv2->tv_usec > in_tv1->tv_usec) { out_tv->tv_usec = 1000000 + in_tv1->tv_usec - in_tv2->tv_usec; out_tv->tv_sec = in_tv1->tv_sec - in_tv2->tv_sec - 1; } else { out_tv->tv_usec = in_tv1->tv_usec - in_tv2->tv_usec; out_tv->tv_sec = in_tv1->tv_sec - in_tv2->tv_sec; } } /* Airware PPI gps conversion code from Johnny Csh */ /* * input: a unsigned 32-bit (native endian) value between 0 and 3600000000 (inclusive) * output: a signed floating point value betwen -180.0000000 and + 180.0000000, inclusive) */ double fixed3_7_to_double(u_int32_t in) { int32_t remapped_in = in - (180 * 10000000); double ret = (double) ((double) remapped_in / 10000000); return ret; } /* * input: a native 32 bit unsigned value between 0 and 999999999 * output: a positive floating point value between 000.0000000 and 999.9999999 */ double fixed3_6_to_double(u_int32_t in) { double ret = (double) in / 1000000.0; return ret; } /* * input: a native 32 bit unsigned value between 0 and 999.999999 * output: a signed floating point value between -180000.0000 and +180000.0000 */ double fixed6_4_to_double(u_int32_t in) { int32_t remapped_in = in - (180000 * 10000); double ret = (double) ((double) remapped_in / 10000); return ret; } /* * input: a native 32 bit nano-second counter * output: a signed floating point second counter */ double ns_to_double(u_int32_t in) { double ret; ret = (double) in / 1000000000; return ret; } /* * input: a signed floating point value betwen -180.0000000 and + 180.0000000, inclusive) * output: a unsigned 32-bit (native endian) value between 0 and 3600000000 (inclusive) */ u_int32_t double_to_fixed3_7(double in) { if (in < -180 || in >= 180) return 0; //This may be positive or negative. int32_t scaled_in = (int32_t) ((in) * (double) 10000000); //If the input conditions are met, this will now always be positive. u_int32_t ret = (u_int32_t) (scaled_in + ((int32_t) 180 * 10000000)); return ret; } /* * input: a signed floating point value betwen -180000.0000 and + 180000.0000, inclusive) * output: a unsigned 32-bit (native endian) value between 0 and 3600000000 (inclusive) */ u_int32_t double_to_fixed6_4(double in) { if (in < -180000.0001 || in >= 180000.0001) return 0; //This may be positive or negative. int32_t scaled_in = (int32_t) ((in) * (double) 10000); //If the input conditions are met, this will now always be positive. u_int32_t ret = (u_int32_t) (scaled_in + ((int32_t) 180000 * 10000)); return ret; } /* * input: a positive floating point value between 000.0000000 and 999.9999999 * output: a native 32 bit unsigned value between 0 and 999999999 */ u_int32_t double_to_fixed3_6(double in) { u_int32_t ret = (u_int32_t) (in * (double) 1000000.0); return ret; } /* * input: a signed floating point second counter * output: a native 32 bit nano-second counter */ u_int32_t double_to_ns(double in) { u_int32_t ret; ret = in * (double) 1000000000; return ret; } int StringToBool(string s, int dvalue) { string ls = StrLower(s); if (ls == "true" || ls == "t") { return 1; } else if (ls == "false" || ls == "f") { return 0; } return dvalue; } string StringAppend(string s, string a, string d) { if (s.length() == 0) return a; if (s.length() > d.length() && s.substr(s.length() - d.length(), d.length()) == d) return s + a; return s + d + a; } kismet-2013-03-R1b/plugin-alertsyslog/0000775000175000017500000000000012124602454017317 5ustar dragorndragornkismet-2013-03-R1b/plugin-alertsyslog/Makefile0000664000175000017500000000157712124602454020771 0ustar dragorndragorn# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ CFLAGS += -I/usr/include -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I/usr/include -I$(KIS_INC_DIR) -g -fPIC PLUGOBJS = alertsyslog.o PLUGOUT = alertsyslog.so all: $(PLUGOUT) $(PLUGOUT): $(PLUGOBJS) $(LD) $(PLUGINLDFLAGS) $(PLUGOBJS) -o $(PLUGOUT) $(LIBS) install: $(PLUGOUT) mkdir -p $(DESTDIR)/$(plugindir) install -o $(INSTUSR) -g $(INSTGRP) -m 644 $^ $(DESTDIR)/$(plugindir)/$^ userinstall: $(PLUGOUT) mkdir -p ${HOME}/.kismet/plugins/ install $(PLUGOUT) ${HOME}/.kismet/plugins/$(PLUGOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CXXFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/plugin-alertsyslog/README0000664000175000017500000000255312124602454020204 0ustar dragorndragornKismet-ALERTSYSLOG 1. What is Kismet-ALERTSYSLOG 2. Compiling 3. Installing 4. Using 1. What is Kismet-ALERTSYSLOG Kismet-ALERTSYSLOG is a Kismet plugin which provides a bridge from the Kismet alert system to standard unix syslog services. Alerts are logged as LOG_CRIT under the USER service. The syslog ID is the name assigned to the Kismet server. 2. Compiling Compiling the Kismet-ALERTSYSLOG plugin requires the Kismet source be installed and configured. By default, Kismet-ALERTSYSLOG expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-alertsyslog/ KIS_SRC_DIR=/home/foo/src/kismet make 4. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-ptw KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-ptw make userinstall 5. Using Once the plugin is loaded, Kismet will automatically log alerts to syslog. kismet-2013-03-R1b/plugin-alertsyslog/alertsyslog.cc0000664000175000017500000000627612124602454022211 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GlobalRegistry *globalreg = NULL; int alertsyslog_chain_hook(CHAINCALL_PARMS) { kis_alert_component *alrtinfo = NULL; if (in_pack->error) return 0; // Grab the alerts alrtinfo = (kis_alert_component *) in_pack->fetch(_PCM(PACK_COMP_ALERT)); if (alrtinfo == NULL) return 0; for (unsigned int x = 0; x < alrtinfo->alert_vec.size(); x++) { syslog(LOG_CRIT, "%s server-ts=%u bssid=%s source=%s dest=%s channel=%u %s", alrtinfo->alert_vec[x]->header.c_str(), (unsigned int) alrtinfo->alert_vec[x]->tm.tv_sec, alrtinfo->alert_vec[x]->bssid.Mac2String().c_str(), alrtinfo->alert_vec[x]->source.Mac2String().c_str(), alrtinfo->alert_vec[x]->dest.Mac2String().c_str(), alrtinfo->alert_vec[x]->channel, alrtinfo->alert_vec[x]->text.c_str()); } return 1; } int alertsyslog_unregister(GlobalRegistry *in_globalreg) { return 0; } int alertsyslog_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->kismet_instance != KISMET_INSTANCE_SERVER) { _MSG("Not initializing alertsyslog plugin, not running on a server.", MSGFLAG_INFO); return 1; } openlog(globalreg->servername.c_str(), LOG_NDELAY, LOG_USER); globalreg->packetchain->RegisterHandler(&alertsyslog_chain_hook, NULL, CHAINPOS_LOGGING, -100); return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "ALERTSYSLOG"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "ALERTSYSLOG Plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = alertsyslog_register; data->plugin_unregister = alertsyslog_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } kismet-2013-03-R1b/packetdissectors.h0000664000175000017500000001134612124602454017203 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETDISSECTORS_H__ #define __PACKETDISSECTORS_H__ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include "globalregistry.h" #include "kis_netframe.h" #include "packetchain.h" #include "macaddr.h" #include "filtercore.h" /* * Basic built-in Kismet dissectors that handle ieee80211 dissection and * data dissection. This should be instantiated from main() and left alone * for the most part, we're just wrapped in a class so that we can easily track * our alert references and so that main() isn't making a pile of random * links */ // Protocol stuff enum WEPKEY_fields { WEPKEY_origin, WEPKEY_bssid, WEPKEY_key, WEPKEY_decrypted, WEPKEY_failed }; // Protocol hooks int proto_WEPKEY(PROTO_PARMS); int clicmd_LISTWEPKEYS_hook(CLIENT_PARMS); int clicmd_ADDWEPKEY_hook(CLIENT_PARMS); int clicmd_DELWEPKEY_hook(CLIENT_PARMS); int clicmd_STRINGS_hook(CLIENT_PARMS); int clicmd_STRINGSFILTER_hook(CLIENT_PARMS); // Basic dissector hooks int kis_80211_dissector(CHAINCALL_PARMS); int kis_turbocell_dissector(CHAINCALL_PARMS); int kis_data_dissector(CHAINCALL_PARMS); int kis_string_dissector(CHAINCALL_PARMS); // Basic decryptor hooks int kis_wep_decryptor(CHAINCALL_PARMS); // Basic mangler hooks int kis_wep_mangler(CHAINCALL_PARMS); // Strings protocol enum STRINGS_fields { STRINGS_bssid, STRINGS_source, STRINGS_dest, STRINGS_string, STRINGS_maxfield }; typedef struct { string text; mac_addr bssid; mac_addr source; mac_addr dest; } string_proto_info; int proto_STRINGS(PROTO_PARMS); // String reference class kis_string_info : public packet_component { public: kis_string_info() { self_destruct = 1; } vector extracted_strings; }; // Wep keys typedef struct { int fragile; mac_addr bssid; unsigned char key[WEPKEY_MAX]; unsigned int len; unsigned int decrypted; unsigned int failed; } wep_key_info; class KisBuiltinDissector { public: KisBuiltinDissector(); KisBuiltinDissector(GlobalRegistry *in_globalreg); ~KisBuiltinDissector(); int ieee80211_dissector(kis_packet *in_pack); int basicdata_dissector(kis_packet *in_pack); int basicstring_dissector(kis_packet *in_pack); int wep_data_decryptor(kis_packet *in_pack); int wep_data_mangler(kis_packet *in_pack); int GetIEEETagOffsets(unsigned int init_offset, kis_datachunk *in_chunk, map > *tag_cache_map); int WPACipherConv(uint8_t cipher_index); int WPAKeyMgtConv(uint8_t mgt_index); void SetStringExtract(int in_extr); void AddWepKey(mac_addr bssid, uint8_t *key, unsigned int len, int temp); void BlitKeys(int in_fd); // Transform an encrypted chunk into a plaintext chunk, abstracted for use // by other components static kis_datachunk *DecryptWEP(kis_ieee80211_packinfo *in_packinfo, kis_datachunk *in_chunk, unsigned char *in_key, int in_key_len, unsigned char *in_id); protected: int cmd_listwepkeys(CLIENT_PARMS); int cmd_addwepkey(CLIENT_PARMS); int cmd_delwepkey(CLIENT_PARMS); int cmd_strings(CLIENT_PARMS); int cmd_stringsfilter(CLIENT_PARMS); GlobalRegistry *globalreg; int netstumbler_aref; int nullproberesp_aref; int lucenttest_aref; int msfbcomssid_aref; int msfdlinkrate_aref; int msfnetgearbeacon_aref; int longssid_aref; int disconcodeinvalid_aref; int deauthcodeinvalid_aref; int dhcp_clientid_aref; int client_wepkey_allowed; macmap wepkeys; int dissect_data; FilterCore *string_filter; int dissect_strings; int dissect_all_strings; macmap string_nets; int listwepkey_cmdid; int addwepkey_cmdid; int delwepkey_cmdid; int strings_cmdid; int stringsfilter_cmdid; int blit_time_id; unsigned char wep_identity[256]; friend int clicmd_LISTWEPKEYS_hook(CLIENT_PARMS); friend int clicmd_ADDWEPKEY_hook(CLIENT_PARMS); friend int clicmd_DELWEPKEY_hook(CLIENT_PARMS); friend int clicmd_STRINGS_hook(CLIENT_PARMS); friend int clicmd_STRINGSFILTER_hook(CLIENT_PARMS); }; #endif kismet-2013-03-R1b/darwin_wificontrol.m0000664000175000017500000000575112124602454017544 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define __IN_OBJC_FILE__ #import #include #include #include #include #import "darwin_wificontrol.h" /* From Macstumber rev-eng darwin headers */ WIErr wlc_ioctl(WirelessContextPtr ctx, int command, int bufsize, void *buffer, int outsize, void *out) { if (!buffer) bufsize = 0; int *buf = (int *) malloc(bufsize+8); buf[0] = 3; buf[1] = command; if (bufsize && buffer) { memcpy(&buf[2], buffer, bufsize); } return WirelessPrivate(ctx, buf, bufsize+8, out, outsize); } @implementation DarwinWifi -(DarwinWifi *) initWithInterface: (NSString *) n { self = [super init]; if (self) { [self setIfname:n]; [self setPool]; [self setBundle]; } return self; } -(void) setIfname: (NSString *) n { iface = n; } -(void) setPool { pool = [[NSAutoreleasePool alloc] init]; } -(BOOL) getSupportMonitor { return [iface supportsMonitorMode]; } -(BOOL) getCoreWireless { return (iface != nil); } -(void) setBundle { bundle = [[NSBundle alloc] initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"]; CWI_class = [bundle classNamed:@"CWInterface"]; if (CWI_class != nil) { iface = [CWI_class interfaceWithName:ifname]; ctx = nil; } else { iface = nil; WirelessAttach(&ctx, 0); } } -(NSArray *) getSupportedChannels { NSArray *ret = nil; // We only know how to return the channels on corewireless if (iface != nil) { ret = [iface supportedChannels]; } return ret; } -(void) disAssociate { if (iface != nil) { [iface disassociate]; } else if (ctx != nil) { // Disassociate wlc_ioctl(ctx, 52, 0, NULL, 0, NULL); } } -(BOOL) setChannel: (unsigned int) c error: (char *) e { NSError *wcerr; BOOL ret; if (iface != nil) { [iface disassociate]; ret = [iface setChannel:c error:&wcerr]; if (!ret) { snprintf(e, 1024, "%s", [[wcerr localizedDescription] cString]); } return ret; } else if (ctx != nil) { // Disassociate wlc_ioctl(ctx, 52, 0, NULL, 0, NULL); // Set channel wlc_ioctl(ctx, 30, 8, &c, 0, NULL); return 1; } snprintf(e, 1024, "Missing CoreWireless -and- older Darwin config info"); return 0; } @end; kismet-2013-03-R1b/ruby/0000775000175000017500000000000012124602454014434 5ustar dragorndragornkismet-2013-03-R1b/ruby/kismet_list.rb0000775000175000017500000000235612124602454017321 0ustar dragorndragorn#!/usr/bin/env ruby # Very basic demo using the Kismet Ruby code to extract a list of networks # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'kismet' def bssidcb(proto, fields) puts "Kismet saw network #{fields['bssid']} manuf #{fields['manuf']} on channel #{fields['channel']}" end def bssiddiecb(text) puts "BSSID ack" $k.kill exit end $k = Kismet.new() $k.connect() $k.run() $k.subscribe("bssid", ["bssid", "manuf", "channel"], Proc.new {|*args| bssidcb(*args)}, Proc.new {|*args| bssiddiecb(*args)}) $k.wait() kismet-2013-03-R1b/ruby/kismet_addsource.rb0000775000175000017500000000356012124602454020315 0ustar dragorndragorn#!/usr/bin/env ruby # basic tool for adding sources to Kismet runtime # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'kismet' require 'pp' require 'optparse' host = "localhost" port = 2501 $nacks = 0 $nsrc = 0 def addsourcecb(text) if text != "OK" puts "ERROR: Failed to add source, #{text}" end $nacks = $nacks + 1 if $nacks = $nsrc puts "INFO: All sources added" $k.kill end end options = {} OptionParser.new do |opts| opts.banner = "Usage: addsource.rb [options] interface[:sourceopts] ..." opts.on("--host HOST", "Connect to server on host") do |h| options[:host] = h end opts.on("--port PORT", "Connect to server on PORT") do |p| opts[:port] = p end end.parse! if options[:host] host = options[:host] end if options[:port] if options[:port].match(/[^0-9]+/) != nil puts "ERROR: Invalid port, expected number" exit end port = options[:port].to_i end puts "INFO: Connecting to Kismet server on #{host}:#{port}" $nsrc = ARGV.length $k = Kismet.new(host, port) $k.connect() $k.run() ARGV.each { |s| puts "INFO: Adding source #{s}" $k.command("ADDSOURCE #{s}", Proc.new {|*args| addsourcecb(*args)}) } $k.wait kismet-2013-03-R1b/ruby/kismet_sql.rb0000775000175000017500000000644312124602454017146 0ustar dragorndragorn#!/usr/bin/env ruby # Very basic example for logging Kismet data to SQLite # Would need to be expanded for more fields and better logging, # contributions happily accepted # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'kismet' require 'pp' require "getopt/long" require "sqlite3" include Getopt def Mac2Int(mac) #puts "#{mac[0,2]} #{mac[3,2]} #{mac[6,2]} #{mac[9,2]} #{mac[12,2]} #{mac[15,2]}" i = 0 i = i + (mac[0,2].to_i(16) << (5 * 8)) i = i + (mac[3,2].to_i(16) << (4 * 8)) i = i + (mac[6,2].to_i(16) << (3 * 8)) i = i + (mac[9,2].to_i(16) << (2 * 8)) i = i + (mac[12,2].to_i(16) << (1 * 8)) i = i + mac[15,2].to_i(16) return i end def Int2Mac(macint) m = "" m = m + ((macint >> (5 * 8)) & 0xFF).to_s(16) + ":" m = m + ((macint >> (4 * 8)) & 0xFF).to_s(16) + ":" m = m + ((macint >> (3 * 8)) & 0xFF).to_s(16) + ":" m = m + ((macint >> (2 * 8)) & 0xFF).to_s(16) + ":" m = m + ((macint >> (1 * 8)) & 0xFF).to_s(16) + ":" m = m + ((macint) & 0xFF).to_s(16) return m end def bssidcb(proto, fields) $db.execute("BEGIN TRANSACTION") mi = Mac2Int(fields['bssid']) r = $db.execute("SELECT bssid FROM bssid WHERE bssid=#{mi}") if (r.length == 0) puts "INFO: new network #{fields["bssid"]}" $db.execute("INSERT INTO bssid (bssid, type, channel, firsttime, lasttime) VALUES (#{mi}, #{fields['type']}, #{fields['channel']}, #{fields['firsttime']}, #{fields['lasttime']})") else puts "INFO: updating network #{fields["bssid"]}" $db.execute("UPDATE bssid SET type=#{fields['type']}, channel=#{fields['channel']}, lasttime=#{fields['lasttime']} WHERE bssid=#{mi}") end $db.execute("COMMIT") end host = "localhost" port = 2501 sqlfile = "kismet.sql3" opt = Long.getopts( ["--host", "", REQUIRED], ["--port", "", REQUIRED], ["--database", "", REQUIRED] ) if opt["host"] host = opt["host"] end if opt["port"] if opt["port"].match(/[^0-9]+/) != nil puts "ERROR: Invalid port, expected number" exit end port = opt["port"].to_i end if opt["database"] sqlfile = opt["database"] end puts "INFO: Connecting to Kismet server on #{host}:#{port}" puts "INFO: Logging to database file #{sqlfile}" if not File::exists?(sqlfile) $db = SQLite3::Database.new(sqlfile) $db.execute("BEGIN TRANSACTION") $db.execute("CREATE TABLE bssid ( bssid INTEGER PRIMARY KEY, type INTEGER, channel INTEGER, firsttime INTEGER, lasttime INTEGER )") $db.execute("COMMIT") else $db = SQLite3::Database.new(sqlfile) end $k = Kismet.new(host, port) $k.connect() $k.run() $k.subscribe("bssid", ["bssid", "type", "channel", "firsttime", "lasttime"], Proc.new {|*args| bssidcb(*args)}) $k.wait() kismet-2013-03-R1b/ruby/kismet_alert_syslog.rb0000775000175000017500000000421212124602454021046 0ustar dragorndragorn#!/usr/bin/env ruby # Basic example of logging Kismet alerts to Syslog with the Ruby client code # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'kismet' require 'pp' require "getopt/long" require 'syslog' include Getopt def alertcb(proto, fields) # *CAPABILITY: ALERT sec,usec,header,bssid,source,dest,other,channel,text,phytype puts("#{fields['header']} bssid=#{fields['bssid']} server-ts=#{fields['sec']} source=#{fields['source']} dest=#{fields['dest']} channel=#{fields['channel']} #{fields['text']}"); Syslog.log(Syslog::LOG_CRIT, "#{fields['header']} server-ts=#{fields['sec']} bssid=#{fields['bssid']} source=#{fields['source']} dest=#{fields['dest']} channel=#{fields['channel']} #{fields['text']}"); end host = "localhost" port = 2501 logid = "kismet" opt = Long.getopts( ["--host", "", REQUIRED], ["--port", "", REQUIRED], ["--logid", "", REQUIRED] ) if opt["host"] host = opt["host"] end if opt["port"] if opt["port"].match(/[^0-9]+/) != nil puts "ERROR: Invalid port, expected number" exit end port = opt["port"].to_i end if opt["logid"] logid = opt["logid"] end puts "INFO: Connecting to Kismet server on #{host}:#{port}" puts "INFO: Logging to syslog, id #{logid}" Syslog.open(logid, Syslog::LOG_NDELAY, Syslog::LOG_USER) $k = Kismet.new(host, port) $k.connect() $k.run() $k.subscribe("alert", ["header", "sec", "bssid", "source", "dest", "channel", "text"], Proc.new {|*args| alertcb(*args)}) $k.wait() kismet-2013-03-R1b/ruby/kismet_shootout.rb0000775000175000017500000002053212124602454020226 0ustar dragorndragorn#!/usr/bin/env ruby # Moderately complex example of using Rub with Kismet, compares the relative # performance of multiple wifi cards on a Kismet server # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'kismet' require 'pp' require 'optparse' host = "localhost" port = 2501 $cards = [] $channel = 6 $start_time = 0 # Have not locked cards to a channel yet $channel_locked = 0 # Have not found all the cards we wanted, yet $cards_found = 0 # Found cards with UUIDs $uuid_cards = {} # card records by uuid # contains { printed = 0/1, packets = #, last_packets = #, orig_packets = # } $card_records = {} # #of lines we've printed $lines_per_header = 10 $num_printed = 10 # output type (std, pretty, csv) $output_type = "std" def sourcecb(proto, fields) if fields["error"] != "0" puts "ERROR: Source #{fields['interface']} went into error state" $k.kill end if $cards_found == 0 if $cards.include?(fields["interface"]) $uuid_cards[fields["interface"]] = fields["uuid"] puts "INFO: Found card UUID #{fields['uuid']} for #{fields['interface']}" end end if $channel_locked > 0 # Add one per source # Once we've seen all the sources we expect to see twice, we start outputting # tracking data if $channel_locked > $cards.length * 2 if $start_time == 0 $start_time = Time.now.to_i puts "INFO: Started at " + Time.now.inspect end if $card_records.include?(fields["uuid"]) and $cards.include?(fields["interface"]) # If we've seen this before, start the scan and print cycle r = $card_records[fields["uuid"]] r["printed"] = 0 r["last_packets"] = r["packets"] r["packets"] = fields["packets"].to_i - r["orig_packets"] $card_records[fields["uuid"]] = r all_updated = 1 $card_records.each { |cr| if cr[1]["printed"] == 1 or cr[1]["last_packets"] == 0 all_updated = 0 break end } if all_updated == 1 str = "" total = 0 lasttotal = 0 best = 0 if $num_printed == $lines_per_header puts hstr = "" if $output_type == "pretty" hstr = sprintf("%s %6.6s %5.5s %8.8s %4.4s", hstr, "", "PPS", "Packets", "Pcnt") else $cards.each { |c| hstr = sprintf("%s %6.6s %5.5s %8.8s %4.4s", hstr, c, "PPS", "Total", "Pcnt") } end hstr = sprintf("%s %6.6s %6.6s", hstr, "Total", "Elpsd") puts hstr # Stupid kluge for pretty output if $output_type == "pretty" $cards.each { puts } puts end # Only reset for std, meaning don't print headers for pretty if $output_type == "std" $num_printed = 0 end end $card_records.each { |cr| total = total + cr[1]["packets"] lasttotal = lasttotal + cr[1]["last_packets"] best = cr[1]["packets"] if cr[1]["packets"] > best } if $output_type == "pretty" # Go back up N cards print "\x1b[1F\x1b[2K" * ($card_records.length + 1) $card_records.each { |cr| cr[1]["printed"] = 1 printf(" %6.6s %5.5s %8.8s %3d%%\n", cr[1]["interface"], cr[1]["packets"] - cr[1]["last_packets"], cr[1]["packets"], (cr[1]["packets"].to_f / best.to_f) * 100) } t = Time.now.to_i - $start_time tu = "" if t > 60*60 th = t/60/60 tu = "#{th}h" t = t - (th * 3600) end if t > 60 tm = t / 60 tu += "#{tm}m" t = t - (tm * 60) end if t tu += "#{t}s" end printf(" %6.6s %5.5s %8.8s %4.4s %6.6s %6.6s\n", "", "", "", "", total - lasttotal, tu) else $card_records.each { |cr| cr[1]["printed"] = 1 cname = "" cname = cr[1]["interface"] if $output_type == "pretty" str = sprintf("%s %6.6s %5.5s %8.8s %3d%%", str, cname, cr[1]["packets"] - cr[1]["last_packets"], cr[1]["packets"], (cr[1]["packets"].to_f / best.to_f) * 100) } t = Time.now.to_i - $start_time tu = "" if t > 60*60 th = t/60/60 tu = "#{th}h" t = t - (th * 3600) end if t > 60 tm = t / 60 tu += "#{tm}m" t = t - (tm * 60) end if t tu += "#{t}s" end str = sprintf("%s %6.6s %6.6s", str, total - lasttotal, tu) puts str end $num_printed = $num_printed + 1 end elsif $cards.include?(fields["interface"]) r = {} r["interface"] = fields["interface"] r["printed"] = 0 r["last_packets"] = 0 r["orig_packets"] = fields["packets"].to_i r["packets"] = fields["packets"].to_i - r["orig_packets"] $card_records[fields["uuid"]] = r end else $channel_locked = $channel_locked + 1 end end end def lockcback(text) if text != "OK" puts "ERROR: Failed to lock source to channel: #{text}" $k.kill exit end end def sourcecback(text) if $uuid_cards.length != $cards.length puts "ERROR: Couldn't find specified cards:" $cards.each { |c| puts "\t#{c}" if not $uuid_cards.include?(c) } $k.kill else $cards_found = 1 puts "INFO: Locking #{$cards.join(", ")} to channel #{$channel}" $uuid_cards.each { |c| $k.command("HOPSOURCE #{c[1]} LOCK #{$channel}", Proc.new {|*args| lockcback(*args)}) } $channel_locked = 1 puts("INFO: Waiting for sources to settle on channel...") end end # No sources specified, print out the list of sources Kismet knows about def nosourcecb(proto, fields) errstr = "" if fields['error'] != "0" errstr = "[IN ERROR STATE]" end puts "\t#{fields['interface']}\t#{fields['type']}\t#{errstr}" end # As soon as we get the ack for this command, kill the connection, because # we're in no-sources-specified mode def nosourceack(text) $k.kill end options = {} OptionParser.new do |opts| opts.banner = "Usage: shootout.rb [options] source1 ... sourceN" opts.on("--host HOST", "Connect to server on host") do |h| options[:host] = h end opts.on("--port PORT", "Connect to server on PORT") do |p| options[:port] = p end opts.on("--channel CHANNEL", "Test on CHANNEL (default 6)") do |c| options[:channel] = c end opts.on("--pretty", "Format output with pretty ANSI codes") do options[:pretty] = true end end.parse! if options[:host] host = options[:host] end if options[:port] if options[:port].match(/[^0-9]+/) != nil puts "ERROR: Invalid port, expected number" exit end port = options[:port].to_i end if options[:channel] if options[:channel].match(/[^0-9]+/) != nil puts "ERROR: Invalid channel, expected number" exit end $channel = options[:channel].to_i end if options[:pretty] $output_type = "pretty" end $cards = ARGV puts "INFO: Kismet NIC Shootout" puts " Compare capture performance of multiple NICs" puts puts "INFO: Connecting to Kismet server on #{host}:#{port}" $k = Kismet.new(host, port) begin $k.connect() rescue Errno::ECONNREFUSED puts "ERROR: Kismet server not running (connection refused)" puts "ERROR: Will retry connecting in 5 seconds" sleep(5) retry end $k.run() if $cards.length == 0 puts "ERROR: No capture sources specified. Available capture sources:" $k.subscribe("source", ["interface", "type", "username", "error"], Proc.new {|*args| nosourcecb(*args)}, Proc.new {|*args| nosourceack(*args)}) $k.wait exit end puts "INFO: Testing sources #{$cards.join(", ")} on channel #{$channel}" # Print a header line $num_printed = $lines_per_header $k.subscribe("source", ["interface", "type", "username", "channel", "uuid", "packets", "error"], Proc.new {|*args| sourcecb(*args)}, Proc.new {|*args| sourcecback(*args)}) $k.wait #$k = Kismet.new(host, port) # #$k.connect() # #$k.run() # #$k.subscribe("bssid", ["bssid", "type", "channel", "firsttime", "lasttime"], Proc.new {|*args| bssidcb(*args)}) # #$k.wait() kismet-2013-03-R1b/ruby/kismet.rb0000775000175000017500000000662112124602454016265 0ustar dragorndragorn#!/usr/bin/env ruby # Kismet protocol Ruby interface # This file is part of Kismet # # Kismet 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 2 of the License, or # (at your option) any later version. # # Kismet 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. # # You should have received a copy of the GNU General Public License # along with Kismet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA require 'socket' require 'time' require 'pp' class Kismet def initialize(host = "localhost", port = 2501) @port = port @host = host @die = 0 @cmd = 0 @callbacks = { } @ackbacks = { } @thr = nil end def connect() @die = 0 @conn = TCPSocket.new(@host, @port) end def run() @thr = Thread.new() { while 1 begin #print @conn.gets() + "\n" parseline @conn.gets() rescue Exception => e pp e raise e break end end } end def sendraw(txd) begin @conn.puts(txd) rescue Exception => e pp e break if @die puts "write error: #{$!}" end end def kill() @die = 1 @conn.close @thr.kill @thr.join if not @thr == nil end def wait() @thr.join end def parseline(line) re = Regexp.new(/\*([A-Z0-9]+): (.*)\n/) md = re.match(line) exit if md == nil #puts md.length #for ss in 1..md.length # puts md[ss] #end return if md.length != 3 p = md[1].upcase if p == "ACK" f = parsedata(["cmdid", "text"], md[2]) id = f['cmdid'].to_i if @ackbacks[id] != nil @ackbacks[id].call(f['text']) @ackbacks[id] = nil end return p end if @callbacks[p] != nil f = parsedata(@callbacks[p][0], md[2]) #puts "#{p} got #{f.length} fields" @callbacks[p][1].call(p, f) end return md[1] end def parsedata(fields, data) in_delim = 0 pos = 0 da = {} f = "" fnum = 0 for pos in 0..data.length - 1 if data[pos, 1] == "\001" and in_delim == 1 in_delim = 0 next elsif data[pos, 1] == "\001" and in_delim == 0 in_delim = 1 next elsif data[pos, 1] == ' ' and in_delim == 0 #puts "#{fields[fnum]} #{f}" da[fields[fnum]] = f fnum = fnum + 1 f = "" next else f << data[pos, 1] end # printf "%c", data[pos] end #puts "#{fields[fnum]} #{f}" da[fields[fnum]] = f return da end def subscribe(proto, fields, hndl, ackback = nil) p = proto.upcase # puts "subscribe #{p} #{fields}" if @callbacks[p] != nil puts "!!! #{p} already declared with fields #{@callbacks[p][0]}, replacing" end @callbacks[p] = [ fields, hndl ] fe = "" fields.each { |f| fe << "#{f}," } if ackback != nil @ackbacks[@cmd] = ackback end sendraw("!#{@cmd} ENABLE #{p} #{fe}\n") @cmd = @cmd + 1 end def unsubscribe(proto) p = proto.upcase @callbacks[p] = nil sendraw("!0 REMOVE #{p}") end def command(command, ackback = nil) if ackback != nil @ackbacks[@cmd] = ackback end sendraw("!#{@cmd} #{command}\n") @cmd = @cmd + 1 end end def genericcb(proto, fields) puts "Proto #{proto} numf #{fields.length}" end kismet-2013-03-R1b/packetsource_darwin.h0000664000175000017500000000435212124602454017664 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_DARWIN_H__ #define __PACKETSOURCE_DARWIN_H__ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(SYS_DARWIN) #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #ifdef HAVE_LOCALRADIOTAP #include "local_ieee80211_radiotap.h" #endif #include "darwin_control_wrapper.h" #define USE_PACKETSOURCE_DARWIN class PacketSource_Darwin : public PacketSource_Pcap { public: PacketSource_Darwin() { fprintf(stderr, "FATAL OOPS: Packetsource_Darwin()\n"); exit(1); } PacketSource_Darwin(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Darwin(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Darwin(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Darwin() { } virtual int OpenSource(); virtual int FetchChannelCapable() { return 1; } virtual int EnableMonitor(); virtual int DisableMonitor(); virtual int SetChannel(unsigned int in_ch); virtual vector FetchSupportedChannels(string in_interface); protected: virtual void FetchRadioData(kis_packet *in_packet) { }; void *control; int orig_dlt; int cherror_pending; }; #endif /* osx and pcap */ #endif kismet-2013-03-R1b/tcpclient.h0000664000175000017500000000353712124602454015621 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TCPCLIENT_H__ #define __TCPCLIENT_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuf.h" #include "messagebus.h" #include "timetracker.h" #include "clinetframework.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif // Arbitrary 16k ring. #define CLI_RING_LEN (16384) class TcpClient : public NetworkClient { public: TcpClient(); TcpClient(GlobalRegistry *in_globalreg); virtual ~TcpClient(); virtual int Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux); virtual int ConnectSync(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux); protected: virtual int Validate() { return 1; } virtual int ReadBytes(); virtual int WriteBytes(); }; #endif kismet-2013-03-R1b/nl80211_control.h0000664000175000017500000000416012124602454016372 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef __NL80211_CONFIG__ #define __NL80211_CONFIG__ // Use our own defines incase we don't have nl80211 #define nl80211_mntr_flag_none 0 #define nl80211_mntr_flag_fcsfail 1 #define nl80211_mntr_flag_plcpfail 2 #define nl80211_mntr_flag_control 3 #define nl80211_mntr_flag_otherbss 4 #define nl80211_mntr_flag_cookframe 5 struct mac80211_channel_block { string phyname; vector channel_list; }; int mac80211_connect(const char *interface, void **handle, void **cache, void **family, char *errstr); void mac80211_disconnect(void *handle); // Make a vap under mac80211 int mac80211_createvap(const char *interface, const char *newinterface, char *errstr); // Set vap flags int mac80211_setvapflag(const char *interface, vector in_flags, char *errstr); // Set channel using nl80211 instead of SIOCWCHAN int mac80211_setchannel(const char *interface, int channel, unsigned int chmode, char *errstr); int mac80211_setchannel_cache(const char *interface, void *handle, void *family, int channel, unsigned int chmode, char *errstr); string mac80211_find_parent(const char *interface); #define MAC80211_CHANLIST_NO_INTERFACE -2 #define MAC80211_CHANLIST_NOT_MAC80211 -3 #define MAC80211_CHANLIST_GENERIC -4 int mac80211_get_chanlist(const char *interface, vector *chan_list, char *errstr); #endif kismet-2013-03-R1b/wav/0000775000175000017500000000000012124602454014250 5ustar dragorndragornkismet-2013-03-R1b/wav/packet.wav0000664000175000017500000000531012124602454016235 0ustar dragorndragornRIFFÀ WAVEfmt « VAdataœ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿFORMJ8SVXVÿþþÿÿÿÿÿÿÿþÿÿÿþÿÿþÿÿÿÿÿþÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿFORMÞ8SVXVHDR~ «NAMEchinkANNOAudio MasterBODY~ dt €"J€Ò°€"fê–*€æ¬€€äFø6:º€€€€€Øv,@>€€˜€‚ºhB$brúø8€¸2€<^¶F@€¨€œ€ÀÒÆ²Öø€Ò¤€ÎT4þ~DHì(²ºþ€ê.FTæF´ê`¼î ¦(âbÈîÐþÒÈ€0ІH|îøl8¸HÊØøÎ2üÈL¶jú ÈH€ è :¶êªL$ :F²$¸úþ²XXØJBÚ:È,˜ìB¬DºJnÐö0À<Ü Jª`À>ØFÎØ2’þ"œâÂ:ÖXÌ$ØôÀJÜ ôü4äüâPÌ Üæ¶0æ¾@Æø,ê $ÒPÒ^æ¬(úä0âì¸<äøÊ¨ Ìüöμ&¸>êÜ02ì4àBî.üð"Øö ÌÌ*äþòê ì&à>ö& 4Ö(êÚúÔâÖàôÄÖð(( * :þ2ü(ö èðàüÊøÂðÆøÊøâêèð"ô,0$$8<0ö,ìôüüêä ÚÚ æþîæöÜúÎÎÖüèìôìæèî& $.86* þæàâèúîòä â äè êúðäÜÜÜîöòôö(ö" ú$ò"üôðîô üðâ ÜÞèúòòìæèì úüôðòöøòèìôþôðêìôü úððòüþøòöú üþð êèî öö î ìî öúþöîèîúüòììôþþøþ  üòô úúøìèðüðøòöüòòö øþ þüüøüúöö ô üþü þöüþ þò òòöþþþþü øúþ þ  úü úúööòöüþþö úþ þüþþúúüúþüüööúöþþ ú  úøúúúúøþøööþøøþúüúøøü     þüúøþüþüúúúüþüøøüþ þ  þúþþüüþøþüüþþüþüüþþþþüüüúþþþþþkismet-2013-03-R1b/wav/new.wav0000664000175000017500000003442012124602454015563 0ustar dragorndragornRIFF9WAVEfmt +"Vdataä8÷þýõïíòùÿÿøðìíõüÿüõïîôüúòïòúÿ÷òòùüõò÷þÿ÷òôúùóñ÷þûôñóûþ÷òóùüõó÷ÿÿøô÷þþùøþ ýûþ  ÿ    ÿ ýÿ üü þúý ÿùúÿ ú÷ûû÷øþþø÷üûö÷úþ  úôïëåÞÕÏÌËÌÎÏÏÐÔÚãíöü$.5:>AEHJJGB<72-(!ÿøðçÝÓÊľº·´²±³¶º¿ÃÉÏÖßèòü "'*++*)&! ÿ÷îåÞØÖ×ÛÞßÞßãìö&,/-*%! õëäàÝÙÕÑÐÓÙáéðöþ#/7;;::;;80# ÿùòéßÖÐÏÒ×Üßãèðü  $$$%'(%øïéäÞØÒÏÐÕÝåíóú #" ÷êÝÓÍÌÐÖÚÜàèô"+/0000-&øéÞ×ÒÎÊÉÊÐÜëú !+5=CDA9.! þñäÙÒÏÑÖÝåí÷"&% üñåØÍÇÆÉÎÔÛãíù&'&" õéÞØ×ÙÝãêòü#''"þôêàÚ×Ùàëø +4:><5'ÿíÞÓÌÇÆÉÓãø -59:7/!ýêÝÕÓ×ßëø$'#õæÜ×ÕÖÜæö&-,$ñáÖÎÊËÓãø(+& ÷å×ÎÉÌØì,461$þìÝÔÑ׿û )*$ ùíåâæò2=?8'óÜÎÆÆÏâû-:>6%ùêâàåïþ  ôßÒÎÓàô !/4/ í×ÉÅÌÞù#+)êÕÈÆÏä/64% óÞÔÒÙèû íáßæö #15.äÎÄÆÖñ)77)ñÜÓÖåþ0:6%èÐÅÇØô+41" øëçëöóáÚßð %7:.øÛÊÉÖð %44% ìØÑÙð(2,øÚÈÆÔð-;:* êÒÈÍßý''óêëö ûéÛÚåù&/)ôÔÀ¿Òò1;.íÒÈÐè*" ïØÐ×î (4,ïÏÁÇã 0@;"þÝÎÓç'"õòù ýìãèú*4+æÈ½Ëî>H8ã»Îó59'çÖÙí&ïâåö%+ç×Ûò-3%ãÓÙñ%&øâÝì ÷ÝÓÜù00òÐÀÉè6@2 Ü¿»Òü(>:ðÏÅÕö)" ñãçø  õãáó&)ðÐÈÛ)>2ãÅÇæ09#ýÝÏÞþ+"åØáü*$åÐÓí/4÷ÔÆÒõ54ðÑÉÙü,$ ìÛÜí ûô÷ÿýñíø #öÛÒå 0>-ÕÀÎû,G>ß¾ÄìBAéÇÅé68éÎÐñ/*ßÎÛÿ$1 ÷ÒÉß 07íÉÄá59êÈÇä34êÎÐê+(êØß÷þêçö ýëèø䨿 (0ïÍÈç=>Ý»Àî*KCϱÀù7R?Ä®Ç?P3ó½²ÕBF㻾ç=3 ÙÃÑû#/õ×Óé êàëñêóÿîêö ëãð  íÜä)ùÛÙò,%äÔå'-ñ×Üú-ýàÙð'#èÛê" ìÞè íÞæ íÛãÿ"î×Üû*òÔÔò1#úÕÌè4/ÙÈÝ 37âÈÔ,:!îÌÐô#8(ûÒÎê3+ÛÐä **æÔá!&ïÛâü öãçú úìîü ùò÷ ýôõ òìôþèâð ÿà×é($ÛÌß /0 ÚÃÕ4:ܽË5B!â»Ãø3G+껽ï/I3ó¾ºç)H7úºâ#E7ÿǼã!@/øÉÆï$8"ðÏÖý$+êÚé ééý óìùøëóëëÿ ðäò ùâã" å×é+!øÓÑö&5äÄÒ6:Ó¼ÙA8Ƚæ%C.ñÃÅö-=äÇÖ/. ÝÓé(øÞãýíæõ  ÷ìó þòô þóõ üïðÿêå÷ïÙâ%&ÚÍé5%ñÈÊù/>ܽÒ?<Ê»å&E.î¿Æþ6AÙ¾Û=0úÊÉø+8߯ß6(ôÉÌü.8×Àà>,ñÂÇþ4AÖ»ÜC4÷ÄÃø2CݾØ>3ýÌÈõ*:âÈà5(øÐÑû(/ ÝÍê2íÏÛ 0.ÖÍò$7æÈÙ 4/ÒÉî"6èÉ×.,ØÎî.îÕá&!âßú# îáò"öãë !åãû# ìÝë #ûàßù! ìÛæÿçãô  ùìð ù÷ýýþúøþ øðõ ñíø ûïñü úõ÷þþýûûýüôóû  ùìîñæð ÿéåø ôæìþíìü óñý ñïýñèõ ùâæ!% èÛï(øÛÞ % åØì!òÝãûâáúæàô êÜì#õÚá%&àØô/ð×ä-*ÞÚû#.ëÚì*øÝâ$#áÜø$ çÙë$ï×à"úÙ×ö$ àÒç%ïÕÝ""ÜÖõ'çÖè'öÚß#$âÛô%ìÛë$öÞå" âàý$ æÛð'ïÙã $!ýÜÙø&æ×é$õÜàåßõ îáï óãì÷ãèÿäáø ëÝì øßâþéàñøçííìýôñý÷ôÿ ÷ñüùìòìéû óçðýîìú ÷ñ÷ ýùûüü÷ø öñú ýðòÿ ÷ñ÷ ÿ÷öüýüüýýþÿú÷ù þóñù øîñ õðù üõøÿúûüúýöóú öíòþîëù  õêñÿïîýõïú ùóû ùôü  ùðø ûìïìæ÷óäìýèçýîçö  óéó  ôéò õæíúåæÿèßô!ðÝåíîíéýèßñçÙç òÛá"#äßý +ðâô)ûåí # çèåâùáÙîàÑâ êÑÙ! üÙÕö(æØî*öàë'#çê #"çæ!äßù$ ä×í&éÑÝ#óÑÑõ#ÝÓì"ç×è ïÛç !öÝå %"àà&+æÝù#0îÚì-!÷Úá&#ÞÜû!àØïãÖè  æÔä #ïÓÚ! ýÙÖö% ã×î'ñÞì'üåí'#éì &&èæ#*ëàø,ñÜê'øÜà àÛöçÞó êÝí  èØæî×ÞùÛÙ÷ ãØî!îÝê öâéûæéÿèéêæý! îãõ$õâí üæéìéþòìý óëù òçó  ðáëõáäûùãáô ëãððèòôëóôêò ùìñðñ øóýõýøý úþ øü þóõ ÿñðü ñíö óìòÿ÷ñõúõù üöú ûóöûñòüýñðùõóùú÷ûûøüûùþ ü÷ûüöùýöù ûû üûùùÿÿøù ÿý ü üøüùôøùõúü÷ý þøü þõöúððüûðïúüðîùöóü öñù õðù õíô õëò úíòö÷øõóîû ðëù óìú õëù÷çñ ûéïîðîîíêïéý ñçø íßì ïßêöâêùãèûáãÿþàÜöäÜôëàô íÞî  êÚë !ôáï%ùßå ùÝÞÿýàÞüäàü# èß÷ ãÕì êÛð(ñÛè "ñÙä "÷ßè 'ûßæ )&àá&&ÞÛý#) ãÚø) æÚõ.ìÜó+çÒé+ïØë/ñÓß )óÒÛ%öÔØ%#ýרÿ%(Û×ü%, ßÖ÷"- áÔô 0äÐì-æÒì1êÎá)êÏã2$öÓÝ -$øÔÛ-)üÔÖ'&üÓÑú$)ÙÔú%+ØÏò - ÝÐð.ÝËè-âÍæ-ãËâ-çËÞ0"òÒà1#ñÌÕ,&ûÔÙ,'ýÓ×,-ÚÙ,.ÙÖÿ,2 ÛÑ÷&/ ÛÎò"4äÑð 3æÐí3æÌã.éÏç1éÌá3$ôÐß 0$õÐÙ-%øÐÖ-*ÿÖ×,,ØØ,-×Òü(/ÚÓù&3 ðÛÚèõðÝÏÖìõçï# "43 *+ÿõëáéöøèÖÎÛìòç×ÑÞñûòãàñù(" "-%!÷÷ ìÛÛêôïÝÐÒâððâÖÙëüõêíÿ ÿ # #& &!øÿ ÷ëíøþ÷çÞàêðìáÜãñû÷ëãéøøòøõøøø '( ýùõòðïðñòòñññòóóòïìêééèæäãâäçëîîîïòøÿ    þûúúúúùöôòððíëçäââäåææææéìðóö÷÷÷÷ø÷÷öõö÷úüýþ   þúøõõöøúûûûûúøöôòðïïðòóõöøúûûú÷ôñïííïñôöùûþÿþüûûýþ    ÿûûüÿÿþûúùöôñïðóö÷÷õòðïîíìíîðñóñïëèåæêïô÷ùùù÷öôôóóôøüþüý      ýøõõöùüüüüúøöóñïðóöúúøôïíîñöøùøöôôôôõõöøùúùöôñòõùüþþûøö÷ùûüüúùùúýþý         ÿýýÿþøõøýý÷óóöøù÷ôóô÷ùûùõòòôöùúúø÷÷÷÷öõõ÷úýýúöòòõûÿÿûöôöüýøöùÿûøúþþúøûýÿ   ÿÿ     ýÿ ýý üøúÿýúûÿúúýþ÷óôùþÿüöòó÷ÿüöôöüüôððôúüúöóóöúýýüùúüÿÿþù÷÷ûþÿûøöùþýùùýÿþÿüùûÿÿýÿ ýý ýü þÿ ÿÿ þ þÿ üý  þûÿù÷ú þúû þ÷÷þ ÿ÷õúûôòù öñõýþôðóýúóôûûóðõþýôðóüøðñøüôòøÿ÷ôøÿÿ÷óöýüüÿþúùþ þùú ûû ýû üøü ýÿ þùû  ûû  ûú  üú þü ûøúþúúþüúýû÷øýüøùýý÷öùþÿûúüÿþúöõùúõöûüøøüÿúööúÿÿúõöúýùùüüùùüýüýÿþÿÿþÿÿþÿÿýÿÿÿÿÿþýýþÿÿþüüýþÿÿýüüýÿÿüúúûýþüüýþÿþüüüþþüúûýÿþüüüýþýýüüýýýýüûúüýýýýýýýþÿþÿþþÿýýüüþýþÿþþüüÿüþÿ þþýýÿûúþýúüüúýûúþÿúúýüøùüÿûøùýýùùýüø÷ûþùööûÿÿù÷ùþýúûüùûýùúÿþûýÿüþýúýÿùøüþùùþÿûüÿÿÿ  ÿýûüýüÿþüþúùüþúúþþúúûøûÿúøüÿûúþýùøüýùùýþúúþû÷øýú÷øþþøöúûúþûúýüùúÿüüþûüýúüýûÿþýÿûüþÿÿÿþþýýÿþýþþýÿþýýÿþýþÿÿýýþÿþÿÿþþÿþýýþÿÿþþÿþüüþÿÿÿþþÿÿÿÿÿÿþþÿÿÿÿþÿÿþþÿÿþþÿÿÿÿÿÿÿþþýýüüüüýþþýýüýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòkismet-2013-03-R1b/wav/alert.wav0000664000175000017500000020225612124602454016105 0ustar dragorndragornRIFF¦WAVEfmt @€>data‚ûÿ2Yzd´D>†fÿ¡þÌþWÿ“ÿ›ÿ·ÿ~ÿ³þ þnþÊÿú¸Ðš0Yÿ7ÿ}ÿ’ÿrÿ]ÿ»þwý÷üäý¤ÿsœéu­è3îÿ×ÿ†ÿ~ÿ¶ÿŒÿÿÄþ,þßýÿþ:ƒ¤‘j×ÿ\ÿ_ÿ¸ÿåÿÔÿ±ÿÿ|ÿxÿäÿ–ßxûÿ^ÿFþþíþ;ÐoÄ'ö¹¾7eÿ¡ÿ‰ÿQÿÅÿfÿ|ýJüŠü£üýœþ¹pû©©kEy±ÿÄþ™þ§þõý±üÇûŽûYü;ýþ³ŠUôÖ5†•/uË`ýuúNúZû<ý×ÿ%ž©¹§þCüÑûõýuTÚrIý^üÃüþøÊPµØ‘þúüÙúùûÌþµ&ÂÁ¯f~ä8Ñ38¦ÿtýÊúùjú³ûåü„þ­'R­F¥ðE¿fw´ÿEýhúOø`ùüÿÎWÔ¯íý‰ü¨ýzýHˆdqþ­üãüÑþ—%Ãþ“úëù,ûòüÕýþœ¡ c?[F’F8ýžùóö÷ÐøqúÏüËÿ  GÑ14gÅ^ö ÿíûÁø‹÷}ø™ù7úÄû þÓGïˆîf@ãÃþUþrþéý-ýÓûGú~ú ücýgÿÐýîl¿=“þÞû°üoþÚþ;ÿ,àþ4üû¿ü&ÿלX …Ø9þ\üƒý¤þåþ ÿøþæüáù|ù¸û–ÿðwºQ=îÙúü§üÞýrüû„ûùùz÷RøÁû½¾'Ë« ʆuÿœý‚ý.ü£ú*ûôúEùçø­ùû)ÿPðá×d,GGÿXýýùýˆþ­ÿ\ýgú4ùgû2ywSaøŠDûgù“ü•OT ÊÂþÿýwþ’ÿÍ»ÿÿ_‘þ ûoø/ùåü_WKçG® ‰ÿ9|Ñ„!ýü;úøxøµûöÿö|AAsÿ¢1GÙ¿âpÿðüÏúúœûyý7þÿüÿdÿéý+ýþZ‹ükÄD þü%ü¾üý}ýþÿeþ–ü?ü³ýrp.^J‹ÿÁýGþ/ÿ§Ä$Ìÿjüµú±ûþT6HÇÚþéûtúñüâ!‰°ó Ï^¡þçú‰ùæùèúæýwèþ£ü ý‹þ6ä•óËàc:GÿUüú·úEü®ü·üŽýý@ü‹þ"˜¬\—o.ŒýùÆögù‘üþ):FþCþ-áÀ•⬾æcûµõÇð‚ï”ô•úŠÿé-Öè.ž‹9Ýÿmü+ùêø÷ùÀúüØþJ¹üJ@kÎïÿ²_!ýú‰ú'ü¶ÿ‰m0%¸ü"øãö¯øªûÊþŽ ŸÀ‘uÿDÿž+ Êøàùöôºó&÷£úý‘‡Õ:iñœl*»ý“ù>õyô3÷Xú•üþ¢ÿš_ôµÇkwûFb|üGø.÷U÷Xù{üþ`þ¡þ ÿþOýÉÿwßc¹X «Âò÷:ôËô?÷}ûÿþòþ-ÿè‚ÿ-úûû @¨Ø‹ý¤úHù–û<ÿbÔ8E¦ÿˆýyýþü»ýoÿCýZûëû,úåú‘ÿÞ7ReB’âœCýîü¼û,÷rõqö$÷/÷ùRþcÙ g © H ƒ[ý[ûÇøö ö÷úùGü·þ!üÓO>¡7hZÿßÿ5þŸüþ> ·h€ÿÿÍÿÅýÍû&ýAþÞü)ý*·W n JònÿˆþEû2öõõíôÚú³¨ìýÄX€@QŒòü“÷bô=òÂðCô¢úÎÿ4¦p p®âžÁ£üýÔù¦õlïíãðËõXüzt4* \æþªp¸¤ÿˆø^ð^í#ï]ô½ý;.áÐ Sðÿ‘´9¹ÿãùJð`éàëzôÀýÍÎ – Á É ¡—ýòþ•Öÿ¹þÃú½ó§ð³ò‘÷ìþeQîd ‹ ÚÊþ_ý§ü³ø‰÷Èú÷û%ú}ûxP©"sZ u B€ÜûiûüÃý8áL‰ŠýÀùhøýñ|(îÖÂ÷åì‹çiíêûÖ )òé «úÍúýü Z_,)ÿà÷óíëuëýõÿ÷C š›xY ç ܘûéõðî:óêû»ÿCû\ùfø¾ü D   FMþ[ù ÷÷ªûäýÅüèþ¡ÿ«úåöˆømü¾¬ù3 ãçƒ ˆû™ú¶ûü¨ÿû`þ™ö8ôÅô•÷"ýB`j ]‚þ‚ÿô) é d @ü7õ-ï~ì†ïˆö?ýI”Æþþ\Z ât-þŽõžíJëwíLóÔùæø¨ö>ú2þ-[ Öd}¶ŽâýJò¶æyç*í,ð6óÉ÷þ˜“du”1‡Œ®‰þ½÷½ïÝí1ïâðèöŒÿa4Ú 3 < LçûIô!ñÊô*û†þo¨pK¡àGÿî$è¿üàúEø]ñîYò´û~m /2½ +Çþâþ1ÿ'ùÆô–ðåëFêŒð]üzF¼¹Mâ<b ô›æú»ô‡ðhéäälì[ùAo ߸W ’  t › P^“ûPø¥ï{è6íTö¸þ§o  ”…0 Ë ‰ñÿýkýdùÐô-÷áû*ýMÿØïü•ûþþQÿœŽhWøÿþÖúä÷hù–ý€~²ÿÏþùû˜û5ÿ* Á oøŽô½òDð‘ôþù^üdþ ÿº•Å?üy3õÉì€êÃëDîbò¯÷§û±ý*·8 Rþ 8S àøÌêcå9åðåôéèï÷ð­ïóhý-qò'ô*Û%°}|ì[ã¥åèyí–òùòiïì®ïºþ“3%-,¡Ì øáçŠå ë°ï8ø³úòýéºèœî¶ÿÈv'Y/)‡åQõ7çÊå`ìôÌýOþ¡ó+ëÝèðÑäÏ%M(4 ¡R‡õ­ë*è¥ñÿ=ŸþYöÇë9éfòs.È…#;¨[tðÓèWëõÅý…ÿèþâüƒøßô;ø@Ä ôF{ üÉîÍéxïùÓÿ9ÑýDýZûü=–’sLøjçŠÜ-ßð›þÓ¡T´*ÇP§&;Çÿ‡é‹ÚÇØ1à¡ìÃù_TŠ  Ø íõ¯ã ówíjñó=õøøCú[ýnþÆ£rsnì KYøôÙõöø ütÿ`¥þëúÎöŒ÷æþ„½ ­%ýäú£û›ÿ{Ízäžü¾ùãü<ÿIýü‰ìŠù‰ùRýþ‹ñû­É.ÿUü U™ÿ–þ™oü¤÷ûïþÄ+‡R“û;öðù£1}¶ýÐýÆÿ$ôÿ¦þ¼ü<ûõ¸ïÿö,ƒC 9¯vV iû³ô‰íç^ì0ùÖî # 6hSâ7- ƃû‘óê¸äCíÎù ÿW×Qt LΉ”.Ó›ý:öJìLåÓë{ú;w£Ðž KZ&þÿ$ÿýúøðñ¡çbå]ïQü²Õ ¾0¬ BÆ(þì÷ÔðÆîMì`í$ô¨úÁþNÿ§…›9€³w#ùZó_ñêò—òÚô û»ýÿÁèf¡ÕòÁ  Nó¯î{ïšóYü}DéPÿnþ¥ý´ýއ  L Ь›ùºóøòiôÉûŽ‘ZÌýþHo“„Ìþü°ø˜÷Óúÿª€¾^ûü|ýìþÃãŸýóö…ñ`ö¤ûÅýÞº ¹)ÿfú ùüfÿÿ<`ý½ú¸úýçúïùs ëÏ«S^þ½ÿFÛüºû û&ö"÷þ½þ³þ†¿0àÒû¿’õ0ãýEö*ôÏùüŒ÷¾ú&·¨bY+ÙN•G‡þùúÝüûúxõ¸õ6ü ÿ"ÿ+²Þ• %  7üÿ½¤û®ú7ýÒûúù«ú…üÿ0œ; m Ö¼ý/þ,þ¾ý¤þˆÿ þëûØù;ùàüÝõÓÒÿaÿ#üJù[úfýCT€g¼ì°€í7ÓóúÖôôî/ííðÝ÷Àÿ–<i n s Z  ? q Ußü}õÕìKåãêÔôfþ¡D zf @ Œ{ +ü¨ìãáè"ô­üÜ¶ß G J# T ËL‚ýµ÷Fñ6ðöñûXQ¿:HÕXK ; (Éø3ò\ïáïŽô4ýñX ï󶜃\Åùø2ðîîïýñ‰öíûÇ 0 ã ‘ : §ù ’^øÀèrä¸éþï¸ô~ûóŽãÑ> X —] üòEìŒêêÇî÷IþæN ´ p —å½ ·*ûÒõÏôcõ8óòñpô™ù3ükü}m ½ Â­Ë jý²ø6ø¾õò•õ´û÷ýþgÿkµz|8 : 0SGúõ9õûýþ[ðÞÑýÎùMöDô1÷Fû]ÿTÿךU™c- ¬ “ ü²ýåô@ëçßè¼îøWÿZj ÅÖ,ØôCûü¿ñeéÒ塿™éï6øwþO O p i•ToDô”å ߰ߨç¼ôjÿ±÷P ò ¹ûc ukù&ùkñríãêÓí]ô>ü¥ê J { ?{ `æ K ëþ÷ïèèÎîKöWü&åd Ô  ( ­ û7 ³Pkóžè>æPëUód÷¢ù/ - u "#Æê †ýÙïÎæmæÜîø¢ùöoúR¬ö™úÁà®øþXöíÅèvì'ñ ñ örüÃý5ö ħà0 ­óbÝýæû¹õìXç#èªîü{ß 1`Öœ£»j 2¶þ"óÙè¤è7ñúûÈéË^ýe•_ 8øs=§ûþòCógúÿEC+þ©ú‚ø·úä+ ÉÂZîÿ5õ,ï$ñ´öîÙëüUùÕü‚† ƒÚÿ(úù÷LøøúøýÝï‚þsûöþÇè   |{ÿÿ6–4ûÄ÷[ùùRø…ü%ó ‰µ1õý?ÿ4ñ© åòŽùðíÁòÖöÌýpu [+U©Œ/}ƒô©þÞùÅøÄõ¯ñÑòöšø"ýþ L`F5 ¿é>üh÷¡÷ùŸùó÷Žó@ð¢ó:ûýÖ =É « ° ¡ g \þÉú÷Gðµëîfø,wŠ 9 w*ÿìý,' ¨ ƒñ¢ö¨è_åËíþú ÜÓ hk÷Íò»øÞÿÏúöñpïõià :P ®Oûù)ÿ{"ÿcôjëeæjè6ñöý [`·‹—ÿ×ÿh[gø£ïŸîËìHí òùs÷ ‚hÔb m { "ûòÀñ…ð!íñê‰î ø4µR ¹ K í _Êþç W:ú¿ñŸè”åfé³ñ—û#þZÿs Iÿ¸‚\ ñ-ë­è–éað/÷Tüµüƒøžÿ§ ¾Êæh¬Íøôþñ,óçó>òô­ø ´%Ó;Í  Øþýî÷õ"õ‚ñ©ñöõæû¢+1à iÑü,ùUúrûèù†÷ŽòùêAç?ë.ù± ©Ñ#Õ›Ðø€òiòô÷Iü÷¸íËæ)æî/úú‡k¯+ å]ÿýûfúÀïÉâ…ÞãŠñ]¶ .aF{ ÷ !F“8ÀüìîSá<àsæòý6ô #9Hî‘ ‡ myþÞùKù=ùAõhò-òñ%ñÆñ|øH ¤ŸÕJ‡•Šný¤÷Çï’ê‚çòæSðCþô‘ø 0µ Ñhž÷þãìÑâûÜcߘêŠõIg ™ £ ; ã B$S, íýØñUìšëÒèèÊì®ôä L‚xµ˜ÊD½›]ùGñóí¹ï4õ•ür>v³¨Ì4 úé÷ëðžðãóôúÞO+JÅý‡ù6ùlûk’ 2 żûCö¸ô ÷ñýüÿ–ÿ@ýÿýôþ­¼­:BÚþèü’ù(ôó*÷%ýË[·^ÿzO –« ¡‹þcû ôÖî¨ì1íöõÌ"¿ÿkJø 9a zþìò íäèêè%ñßû–É/ojîFP lj  !ÿÒø)õ4ôòóÅöQüéfox ÂÿžlˆÿßýŽüÆüãüdûüby °­¼ öûý®øÜöWùœùÂø#ûÙù›ô)òXõ;eP U$§ ý`ïñê9ïýô_û€ýPõ+î-ñ­÷Áþ4 yPMRPùqóÁó‡÷Ëù<ø_ùÀúÚù#þÞCÙ Ç Ô óEý6öBðæîÒó¿ùAÿwè +D „ õ“Zülúføü÷æòìèÀã×èÐöo’ ,)*V÷²ÿöó‹ï<ð{ï÷íÜëuæñèFò…ü. UE',4!çöŸð¤ïˆð£ðõêôâåð‡ ³)U+¤BÖÿôêíôíüðêôMö˜ólóN÷\ú Ñ (+¯{5û‡íƒç•êFõþÀ [ìÿ¶÷‡óáó²÷©Ý ëHçµ²û{ù…¤ d yü`ïšã½Üèáùì‘üÛ ê  n 0«›x.H îäÛ7ÒÎÔ âVóJ <~µ!¯%y êç€ qþøïìvà'Û+Ø–ÙWä[÷u¸!¾#3"qc õÀú•ì\âBÜßܼãuïù½ä‡_2ÿ™?-Ùý^ïúà Ý[â_ðØÓË…6Ù ‘òûàùü·üY÷'ò?ð)ïrôÓV ·Ê. eÈü¸÷zõ/÷ÕøÆ÷{õÜóÁ÷bó QPLÎ jûÑñšïò6îìDõsþ×½À ¨ U ¡.%ø@òïñèyãùê~ùF ¦ñ")6‹âûëó ð+òaö=õŸë8æÁìX÷™(#–-w%ª‹õòëAï©÷kóékä¾åñDŠË">)í#-Ô Îù{îÁñÁð}î×ô‹ûßÿ˜ÌS-˜Ï"gÙ¥ÿ°ýøäðéí^óñ¨"—;ÿ†õlî4êçyêƒòññ¥íçò;ýÍŒ+Y2^*i¬üÞç¥ÛÌÚnà?ååEæîù÷+ÑM$ª+Ž/´'Zïë«Ù*ÑÍ¢ÏÙÙOëJ"0µ4ç&3ë »Šùãðrå·×[Ï›Ôã½ôŒ …,›-¾(«!ÙI XÿëöpêØ“Î.ÓQßšó§ ¯pzN 4Džø'ëŸä$âæ©ðâû ùŸØû ­ùùDö€ñxõ”÷™õªô`ó÷Øûæý°Qª¿Ðý#ùêîGêlðRþ!'Dk 2þ0ôòcö|ù}1 p£ôÊírï·ù[ ­†+8)kÊõ†íúçîéŒó‚ù¢úùv÷¥û-# æ“"ðϧ”ôìë•ïQò¥îñºûäd ¶ .%H6VÿùüõWê¾é˜ð[÷Ò9#Çwwòêé~íÅö‹öíòéHíeø’ ÒLª!g¥ÂGøNëpåTçÈåHè•ñÙú§©ÕJ>®º ÌiüsòÌò#ð•ç¸êUöð‘ü>ç øaòÿñïþæFéó8ú©Ü‡%^$Ëþ õíì#éêÀéëèƒëœñ¹ý ­_"M"¿÷9yôÌë¼ëêDç3çÈìÚø˜¬ q°= (ù+û™ð‡æ^âYèŽóÍüîÿk ¨ã ú ûY ºeùøñéeëú%ûòG ûý¾÷!÷{÷Œøáý,l+ú•ôÃ÷lü—Y¡o•çÞõ6èzÛüØAÜ‘à¢ò¥H‘Å«Óá ƒ K -ÐþŸïÄà™ÑìÈ‚Ôï"á(^1›-¨ Œó/þü_øÿé´ÔñË·Öëžþ¼ ,©7H.]WIüÍíá啿'ë¢î·òõó5õÜþÎ#ôë,²(OágíÚ*Õþápø ={HpÿlüéýþÂ_Â$¯÷gï…ð”ôñþÖg*Ú Œü îåã7ãÖèäôQ ‘ JyñÛć[\þ>ç/Ú5ÕÐÖ§Ý´ð  '$º)´ ¥$ÆéÒè`òkä†ÛÛçåö ëœ* $ÈÍßòø!öùñ–ïÜì¶çÏëšôiûn|Á ½y–Õ ÓüNñ„ìžìƒõ*ÿò b+÷ý–ú8üóÞÙýÿ ûÅükäŸ+øÿrû÷ùñ÷öñ­ì¹ïYùŸˆö /ߌ© ‚k÷ÈïxíPéFäàâ*çú“-!±%&q4¢ý…ôÄêßÜùâÊåìøúò°%j&ÁÊËЩøðê’è’ã¹Þ6ê‰÷ÙÿŽ %š!a~ûÝï8íòòløÞªlÿ¾*ŽcÿÔüMþ¯þžùNùoýùúìýÏÇ µÎ ×Áí­ù:ðBç¬ã«é‡ô¦û÷f ³ è Ð F.¸ýöŽéŠÚŽÖÝÓç™þ‡Ây”  š4$¢êˆò~äöâ*äëƒøS‰_ù * ·¬\Wözé#ÝÞŠäïXü o ž *, /ÛV ÆüQìâfâÔé¤úŠ Œ‘` øŸ#Ma À”ÿñô¹ìréðsú#Š N\ dPø'ëPéñGú¾j.ËÿÅþþü‰þ¤ìriÿó†ï¡íõ+# 4 òýþ¢þ4üãý‡ +6ñþaü°þýEûYþÉ Öü™ù£ø\îŠéÑòäþßÍR.o•ö¸ó÷øù5þöýžñÅë\ðYòbøä1[‰©þG÷eòLôéöÙù&ýsõðüöþ #Ç:F4ýómèTæåðéÿBA+«ÍþÃûšý­üÆøæù£þžý›÷òõEöIözý~ cZùf–bö®î|ìQéîŠü  ! ~Ñ¥€ ˜€ Zükî™ãVâVñ©Œc¯# ¤ 3ýâ÷kôÏñaôáøòAæØå‹í!üÚ  s"¤#"`"þíîžß ÏyÍ3ÞÕñÛâ $ M G»žûW,wðiâà­å_ñÆÇƒ‡ ¹ý³þIü{øðùú ùü YæØl _ û æ,ú<ï¡ììò údމ M…;s[Ÿû—ù{ü÷ãðàðó^ü» ¯Hdážø9ôÌñºè¡çÍò‚û.ÿׅ߯<¦ ýJñùèvì0ø:þÄþ!ÿýÌûýýØ Õ ¨ý®ñðÝòwùåõöŽ›×Òy÷ÐìÒëeò ùÿI¿¢ L§Ä :Áyú!ñ4ãÕHÚô  6’)ÿ2þ™Õ É Zò)ÝÉ×â>ó»s'j#e”õŽé‡ë×ò†ò(òÅôjù Ó" $çt %öî9ÛÛÚìÄý÷ ðG †ÿþÈýjÿá䛇üëøû7C =â/ûÿîÓÝ3׆ÛæOó) µ5¾ Ç;!ã7ñäáy×ÊÚ{è*÷Ãqu˜Š]Åú ñÔí¯íXïæøb[¤N} +‚³û@ò8çòÚAØËã¡úA VÞKL œ  T "côœìièæê‡õýær›øCvƒ _úêŸæòé íö¼ô )Ι‚žS ûíÖÚÓÏOÏäÆZ„ëW èÃíòƒæ³Û)ÝÒçÝðAþ' tÐ?ŽÈ DOÿPö”îáìôÂþí—ØÄü£— Ç ž áú¥ïNìÏðØû4pÍk>þÿmþ&ý©üJø²õ«úŸ!p #ÊÉ#ÿ,õ?îQîñóû ` £ ñ ™¯øòêæDæè›óxa÷À½-œ !CýòžêÿåçÞð±úp’ í j @ŸCÏ ¥6øîXèqé,òŸü¨ ÚRp'7  úñªé?èê ð»úƒî Ð ny á …©†ò#îíîSû< àþ,üÔýHÿÿ:ÿhÎþ¤üÐ÷göÑi z l‚ò±/ýÎôðFê(äæ5òUÎÒ° ÿ~;Ï×ÓöûfóÆî`ïÆöúþ 6•f 0 ùŒòªðað{ôüûïÿc¨ [ bÛ™¥cõ­íÞà¨Ø0ßPê§þ£µ!!P^/ù IÂýµ÷[êŸåâëî~õO ßžŽ¨ áþõ6íèeéíìËñPþ ×­Ägå˜ûþ”ôÿæÍÚ6Ù¤ábòScÞ‚T µRùÃìçé&éµîŽü”Å<lê'ËýÚû‰ô¦èðä¼ç«í®û¨ }£f|PÙöÄæ»Ùø×Oßqë³üÎ iäy ™Ôºx ŸwúÚîé§é#ïìù' ­ Ñ SÈ k)þ¢ïïã5â¼é/ú‰ 6 ßç‰åw Y œþùø´õ¦úóÊ ö¸ýCùTùùøÔö<ô·ò‡õ§û2=¢«ò S e y îåÙÎ$ÏKÛôñ Ÿ!ú%낲̅ ÏÿÉõÿìüäàÃç=öÞÿRú_çî0 ‹ÞöíîêEî”óªû&”â§ %ÒÂìù¸çŸáHå®îú.ÞN  õÍv()ûæþ<þóúý^—Í{ÿSý½üàù”ïŒæ ìUôýúÀ Ý€:G~\ºBñ)ÞÑÒÈÔÕÚdä³õõGK %"&÷úõ–äëÜtÞærò)ý@í uÒ³çyú…õ~òò öGù$ú@ú0ý– ),‘ºyô-ëªæcìØõúŠû&þ‰ÈV@² ºþ9ôÇð—ò øÙ‹÷ùðúóþƒã)ÖùšØöÿ[´Îï° ±,ù¦ðÉí¹éœæï‚ú+z"'Æ,í27øké>ØÎ͙γݓ÷m ›º U¨ç*‰üÉíBâÚ[صÝç öî¸ô$)±$¤3Cþ¡ñ”í¾ëðé$í‰ôK÷ìöÝúTd)7hü/ùZø—ÿÿ¶ Ÿ"ø×ö™ö…ôcóåôrø‹ý“ŸðT À † ü9 Q×ùò³àTÕÙÙÈãö— êš%òJ!a5.ö"à-Ù¸Û†àYìŠúÕ Úg¨õŒÿ¯í¬ëøíhí`óFöèó™õÂýj Š`x ?ü7öîNéï[öœ÷ ûz Ñ 5 ˆ:Öùûô5 å ì÷Šó¡óÑñèõY Êú¢õÂô“úGñ l {‰ü4ù%öíñÙïíòcø ûLþÿ¤v^ZD K` $²øúï(êeæmçÓõÜ nÏ» àýû_½8SïåàÔà»ê«ùØ­-}<íQü,ð…äüåøëWîÜõýþ`¨joä ë‘.õŸð€òôòü] é ßöù:ù÷úAýƒÿ™þDù©øËÿIq ˆ HÿEs«ûúFõõïFîï‡õÜàAš ÊÀû…ñ…ômø:ïÁæ—é`örÞgÑ¢LPýEñ;ãÒÇÑÎÞgíÓþA³ £ËVCž˜·êÐ×›ÐwѶâ¥÷Jû E\6]> ¡ïú*ø3ýGövþ“÷ó3òKøùfð,þýFóÕðMó7úøÎ ¶’ DDéÿ¼þþTúßõ8òÃìëé·ížõn a£¢¦ ßCúsñÒò‡ùDû]ùH÷âò¹îVó Ñ ßÆUÈÂÿžýúÚúÿ›œûŒõ¸ó:ô.ù´‡Ë…Yäïÿ/ûuüŒû¯û2þœûZøEúíÿQ$à ú‚ŸGÖöÉðGô‘öâö!÷’õ—÷ðýr Á qÄðW`wûŸî‡å-éeìÈî>÷‹ý*´ÿ6¨  Ÿ ¹†·Ð·ÓûóŸôZùØ÷Ãún%þMöÕôQúÖúGþ7¤? ¢_þ›÷Áø9ÒIåòôöéHíkö–ú¨ƒÈåÓ“ÿÑöAôõMöŒý"*o„äþ¶ýß× :€ü´ôòìQå]è^÷FgÍÙ €¶º u Û÷ÇéêØïòùæù‹Jž âü>øZò¿íðLüX¶Q.ÁDË&žÞ±ñ}éàçæ{æîû2 nö؉‰éåbOü”ëžâÕßàûæñôù›S3d; / ÄÚ{ü.÷%ïøìið^ðó?; >À … Áˆý~ýÓ ÿ:ü(õ-óoönö{ø‰§ftúÀNù 55àÿ2÷Xò`ò*ðDòoþyÖ©ó 4 êHrù8qÿtóIçŸä€ê¥ògûp9 •ˆ³ ¸oâ4úûôÄðCìòë‚ïçó¦øŠuç} § ™ ô" W• Ïÿíó‚çZÞß6ïÁ© =Ñ`ÔF ¡ D Ë `ÿçòÎéèçêˆï^ü* ¼¶ õ CýÓøû÷ð„íë†ç÷îp mSA zûùUûü‚F7þYîUèöêñÕûµ~u«=-þºúrõ£öËý#þûéýVÿ›ýRÿ^™÷¯ ² Éúùø÷WòeõéýâÿrÑUf½ Ž íÿŽþïø¢ñ²ñªøbë Í Âzÿ"öüûÐüýRø:÷ÀÿM J šâj NÿŒü‚þ´ù¹ó•ñîŠêžï®û<?h Ùî $}ýïqéòëÂé{åÞïL°ifä5 „sü•ô´óÅðˆå[è˜ùÎ)Ø¿ßò § Øûóõcõ…ñ"ëÑíõçùô3´öî þþËõ¡ò÷ðòïªö¯ Ï " ж²ý÷ø?÷ñ ëgíë÷ÈpÜ­ ±CÊ™ÿìõxêÒâ~ßâXìÇønô ¡?1ì+/ù éõâ¨ÛëÛÔì9‡ Ò Q ¨ í‹üÐéšÖŠÙëOøžãº—©à~ 8ûtó¯ê)çÙî#õ)ù"& /e© ¼üVï-åíâïäþÈ äIƒ ¥â « ¨°ý9òäÒâÙìa÷ÆáÀõÍà$̵¤úÎêÉÞãÚë}ò÷þ ˆ ` ª Ô¯“ ¨ž­ø~ñÈõAúÕý4¢ÿPý3ÿÝšÓ &ÿèô¢ì³ôBL r'øüóüèþªûKøhòoç”æÐîiõ·å¹ýõŒôêWé$ê3èîì´ó¦ùœ& 0 ä ä:y`Oð£Ý4Ø|Þjè_öˆý µö½›c ¤ÿôïëUååÙì‡ò¹ùxñ’³œ ¼ Ú2Ÿ.£~ˆ÷pó)ñ×ê ñ‡ýÅýýùþiÿVM O*¬ˆý2ùOîåçPîŒ÷íÿj‡½ [ Ö ~=ò ‘ùºí´è9é€íWù•• Ÿ êj u ± R û Sûñ;ïìî…ö«úÕýL0 Ø -}[ 3Øú‘ñ&ñ*ò]îxñùþnw¯yJŠˆþoû^þݰÿò÷õõœóyô*û•Yo\>ýúú3•„óÔðo ­ Šÿ–øÿó îéõçvñׄh G%Ey¹ ¡ý°ðÒæ ãKãžæ>íõYÛ¥ &‰!<‡øú­ñçëtåžß›Þìàêü Á#9-‹+õ$ay‹ûêï]ç çÕàhÜãâ(îžý–‚‡ö>§ÕM°ûñðˆã áÔç:ï´ø[ÿ¤Ë ›ºp ßDõ 5}. þˆòèé‚ïRòÐøùüUø!ÿ¤×}$9O¼¶÷óë*äææéä>å¼ñwûæeb!ÚÒÆÕ*û;òfê'ØæÓFãƒô½_A>`…õSCÿóòéäã¡ç7ðïýÓ l­° èUÖ z fó$ëXæãäéøòòúH|Cmìïo ªý§õ?î=ähãç€êÅóØþ>Ê 8õœSÝ™ÆýÅóîOáñÙ·áŸï/ý/ ù‰PDß' ˜! õÿÒöýöýõÔïÖð,ü%zåþ«ûÔÿM‹Ö È• vû±îéüïüôõ§úEË:¤I Ô‹Ï@hËøBêÝÛeä(ñ²ù ¢ ÉÛA¯’¶—ÿŸï9âøÞ¥àäãìúÊ> ˆLîãÖ Mý–ö ô–ïçëSëZîìòOúƒM9} þdüuý®úêùtû•ø^õi÷«ø‰÷ÄúF.C< gê ‰2UÌøhî<êäYàmç5ö rkmSa! .þ«î±ÝØÑÃÐåØ&çDùÚ :µ $ JšæÄ Bþ÷Èê“âEݲÚÑà˜îyþ}o 5•òðíüûöoðóïò#óÇôÙùYÿm·rã ¦ýQüýsúö;ò¦öÎÿQ¯(ËøR\ ¯q°GåòÜí,ïïºï4ò‚òañêú®û &™'A&Á{#þô»änܪ×ÓlÙ7ðîËð ?!9ÊÂuºl UöèÚÊÚÊ ÛàòõtÃØ ÞÒ†Ÿ¾õ`ë¨éî9ôÑùüIûxüP" K&ç&ÿ7š¤A·3ôjåàêäíÔô¡ýîûOö5ˆ%­,ß*åÝõ)ìußÿÓˆÒ4ÔÀÖÁéïÏ(*(:j8æ'™ôŒöÝè?Ù±ÆE¿"ÐÊëœV%$ &s*È"ßËÎó¯á7ÔÒ4á_óitJW ʼ ù °2 4²ó1ëtí öBþ`déˆ ©Ï  Ç”û=õóïô®ôõñ‰ðÜñú 7rD $[ø[økûc÷ÍêáÞëæiûµ-Q4""]Œ¹›õÝáUØrÙcá&î5ûÍé Ü ¹ ð&Ú!•ÈøÖâÜ,ä€ôtŒ ÏGúÀòïø±þïÊ-÷ú•ñ÷z$¢UaÊùÇðnéœêœæÝAÛæEüA?(]5û.çø–ëö3òð”Ýîʦ̞ÜîBÙ%·6 0%']"šEyýàñéÝÇÑxÒ@àÁöß h,3 `%ƒ ä)þ7éQ×v×åñô°ÇÂbVàN"¶>ÿçÛfß é÷øÝ kúc(ÇZ¦‹`õ%ê)ì5õ$æ ï "¯þv÷¬óTö¾÷ÊôHêåäxñ–Î#F ÿOû÷Èô=ëÊÝÜÙíåõ÷ˆÁV(t Re=¹ø÷;÷dê_Ýfà™ï‹ƒ%x#æ½ sêø¾ð³ð`è/àëâ-ë úÈ Ñ!Å.Ú*¨ +/ýsí=àeÎéÂôÊàfú{Ï+t1>(q%r&“ó vUñ‡ÙíËÎ Ùþèšÿ/#<âznÓ ãúÌð#ëäìôàüº”Œü÷ûdþPü’ü6EþfõŒóùLS ÆQ“ ߊZ÷%ëYéUåWÝàŽï.þR u &7ÚAŽ âýútö)â™ÌÇ5ÕIî› Ü-‹.‹)Ø Ñ÷þùùAò€éŠé¯æIâÐéùø"Ê ä*Z-,¿Ózì€àhåó™ýòŽ '*øSÌ µ K? Éúöò÷yúÞü½¼~ý™ü*Éþû)ûÐ÷ô‚ù ­ /M MþRó[ô"ô:ï/íÎì3åà´ðS Z$y/p%ÓV~ òòäÂá“ÕïÈ(Ò¶ç'ü¢Ê"ç$Ü!B**$Ü8çôÉž½„ÆñÛ…ó• 9 w%ß ¢yRq þwêÈØ%Ñ÷Ôêâe÷V ÓÃ$%N"5¤ÿºì#ÞõÚÝøåõÛ½ ˜ ¾ Z¨fó© Où%è@ãÐçzðR BÀÝþOÜaùðíëÐçzè¼ô¬/ Lr'— þ÷7ïýèìèØívöÁÿß³êMá ñ  ßþ2íá7ã3évòAÄ!01«v÷=ùkð ãßTääçþîJ³Á§.5¦&›ukõ¡äÂÞƒãˆèîæCëªûÅR“Ý%à%È ![MðŠí´ñ­ï5õþCútëuðÂýà‘ŠóΰúL÷ ù¾ò è /øø1öYòòïò€ö´öôvù§ñÅŒIF l|û¦ïeî4ò3êLä5é£îxñìûF" %0)'=òóÖçsÞ&Ú“ßcíkõÛû¦Á_Ê!Á.Ÿ+æé ×õâPÝâ«äBíÅþPX¹ \µcb}òü•ñ¢ãçÜBä`ò„Œ‡§ ¼YM Dÿû€ì‡åJëVóœýw ðÖ Î<ýÌöóýŠúèþÒ%Ò¸Èÿâÿª–üÃóÊñüô‰ñ»ïJü"†*‡%ç¡TøìòÐê‰ä,æSãõÜ´ã“ô²¶&]-™%¸=óYíé?ÚÒåÝŽòé¶ ñNiW“Šúþ ðïà™Ý:ènø~ÛœÄbd ûÚ÷©öäïìï×þ\ ­ ˜ äøQñ,ø´ü@üõüøûhô ïêöh¼;K üõñIëéðð9óHí„ñÿý» Û120V;éôöâÃØGÜêßÞNåëøý 1Ó+-6D0£!Éo×íßÝäÓ!È}ÅÿÓðúE*…<\;À.é-,ª‰-åÌÌ>¼b¼ÐÊ$áúüÚ·n!Ê0;„3(! ÞAÆåăÐ%ßFô© à  3t¶Æ7Eð½Þ5×Ëàjó‡fé™H ]òÿŸÿ™ûÓúìGãRæ]ð}Žf­ˆ¡äøÈñ&ö/ø˜ôUóÝõã÷—üþ0 RÓÿôFñ÷!øLñèî(üò Sž!){û 1þ^ìÈÝ>Þì݌ٽ߻î­þØ.@¶>·.– é òýâ2Ù=Ê¥Ã`ÈXܳýÍž6¥;H4â/U'+úž÷Ûè׋ƛÅö񱐻 (›.¡+%û›©ýùFíEæúæÆæ_îpýB\ O«ôÂ÷wóKëÖæÆìûùæù aš Í› ò¶üÂùTöƒèÔ×.Öåôõà x(À.Ø$Ìv ÉûoöjóÍìØãØÞòáÒæ˜ðU "%$]'Åx|þËõ+è¥à¯Þòäåóo­!uü åþ©ñàè`ç°ê îÑõ#›ØFJ µõ‰ðïÎîýîêðÀ÷`þ›3´ŠÅ…·ùðSèaæêŒñ^ùÉ) à $ O»üÔð©æhä­ëüöøþ‰Öö ‡= #³âø¡ìýåŽê«ó$H5ÿýøœõ·îÑêÒð<údý ýA±ìþ`ý;½ º4ýñøèîZø£…ºÿüû›ýùþfÿ(ä NVª–ý¥ v |4§÷îãÝçêî—ö¹æ S;#·6ÕÕ =™óÎãPÔYÎâÕšå¼ü!($¢ H³üûðæÞ´ÞEçñµþƒ Ò× sÄ HžûôÔð¶÷Nÿe¸J:¾þÍýþÿ\þÒý·ðéëçôœj $7'þ ö¼ô1ïHòLí˜âÕÜØà#ì´øÆ Fé ó"¸#a™ Sý„ïûãŒß·àYçOñ úOÅ1{Av Dû•îÑäââlèáòCñ®×ÉÜ ß9è æÄýVó*íÏìô%ýö-žwþ×ý~þŠÿÏñùÓôL‰ &0…òbðzì½æ6îØø“ù&úöïŸ!GYÔý™ñ5ã©ãwé?éØðÁýæ˜ hP%K$Ö&¦ü)ã·ÕþÕhÖåÞõ S`(0_'o[ µ®úîçQݤѿÃåÇBàÍÿt#GBäIÂ<í*9 ~öGè£×kÂ2¼ƒÇOÝ…øõ.Ø6 0n0b+hÑŠËéúÕ,ÌpÏBÜ îrÑå õ ù§ ¬-ù“õîó¨øAþÂû^õqôßô¥ò~öWÿ €ÖÕ Ü c£^ vû óœéøØ‹ÕÚfÜ™ëÀ—&ž.!/V"í#ýAîræ9ßÑÒPËðÑç–½$X>>X.#ð¦ôÍëGèfä9à¨áœèRõ™~I%)$Åzš¥óøéCàéÝâåÇîºúr£!5+ä-W(ì³õ;è¤Û¹Õ´×oàúêeû['Ô33æ$ ŒóMç—å±â9ÝÎá ìñÀúlµùT¿. Ô µñ ôéí‡âºÛñâéÈë”õBþgûyýF&$s( (ƒ#Þ ÊïYßwÙêІÏLÕ|Õ ØÙä‰#;rKñKd5Xœ×çtÖþÍYÃŽ½UÆ|ÙÁñ.M.½E—L J°=7#ùVð]Õâ¾o¾/ÍKÜ<éPz*ù.ß6â/$ wù:çݪßËéåðØ÷ýî˜ya H»î]åßíiûlÂ… oLw‚ùØöEõDè¨ÜƒãPö'¹ !S(I ÎÂôNìAÛÅÌœÎÚÜ ð^¶á*W20='*ðBü›ëÝÔ7Ë—Ô­àâë‘þÀ:5$V7Q7ø+Å  ÜíU×çÑÖ Û æ ú( n"UÊ© ûËû¦ô™êããbèúïQò”ù'Fe©˜ô Æ iÑŒü˜òÉîæò)ôöõ¶ûí÷ î¯ïþæ jqv4{âûdøÙîRð÷×î¡èØðáû€v1RSq÷±óÒì«ä¶ß™ãjô• ¿ÂÒ ‰ È”û—î'êfè|íþ* ?v §fô@òlñÀï·ôþÄTªW\ Y¼T÷Uñ°ñ»ê%ç¥ñíZ)"y?¾;ö5æìáËå½á…â„í ü“ Ž»&×.˜,$"eïóíÙÐdÅÃÄÖãë¿:l(,497<æ56¡ýiçˆÌQ±k¯ÄÞŠøH$¶0Ö=IŠCA/ëþõ·Í’·¹±‹¹cË[ã@[Ï^,Ž/ô-[0—%Ø °÷¦ë³ßÄÔVÒŸÖxßÜì€ …1œvƒq ‘ÿvýø’éá…àÛãÂìµø•“NÄÂ0Ùi!± ˆü—ìÓÜnÏ–Ë?Ôßì-w&ä-¨-K*i%±1qüñæÑµ¼Æ¶ÔÈCãÇþ´g4ž; 5?0/+äÒ,ü¶æ:ÊSÄ[Ì:×$èXÿDÎ$¿-ˆ6c+¤a íøCá_ÜqçPðÞõqúƒWâœ3S E “Wó í ñùð죂 ¦°|õõøé’î‡é‰ß½é¢ý ¼²¾ÀÖ€žGðlëMÚÆÎç‰úT !t32.‡)›/ÿzïqߎË}ÇæÑRâ'ôð%Ï#™)ò7A8k&š+ü%Ú¬ÈEÇ<Ï÷ßÎññ&y0*d-)&B#W«ÿèCá=ß–ßMâõìàù\ÿÙ ‚$ÎïÿH÷õº÷7ô»ò_øq÷¹ð[ôžÿÝþþB .y {ÿý'ù¿÷‹úPû*ý¦åüõ‚õTôüìîôÖÛ¹Fƒ€ÿ¿ÿ²úö.úÉòå+åÌíÒöëþÔ ñm!w0÷ØïÕà•Þ>ëAõóúÿýÖÿ–MÖþF7ß 8ù—çàãFë'ô]û‚ˆgý°¶ )D æýEõGó"óµôVùBõV÷>£Ðš‡ œ) • ´žiù]íµåùéî¤ó¯p ½q |QÖz¿ |Ç÷íêlÞÛç¹ï$ð@ÿ=$!}&o çÁgøbù ôéŒìµímåáë®úûM"û"õÉžœüµð£ì`ëÅå"ëöúß K¨ZäOÿAþ-üüûËÿÒû~îŒè\òœþ« !“&§ p åô3ícäÍä_ñsï5ìgù‰G ¾6$ß!ŠPÏú èšÛáôãÝwçf‚T0»9K,¦v:æ5Ò¬Ó¦ÚgÚºâjõ›n¤&è*[.É2dnúlßÚÊ|½È#âh÷TîÝ5Ÿ®DžäUúìãöÏ¶ÏØÝñg‡@o"Å!Æ$þió ìõßqÙ+à¶íùu ÜR$‘%q˜áíÚÎ1ÕêjûŽ» Tìe¥±—›G2ðÇà»æUõ5þ ¢ À ó^ÿ5ùKôýðÙéIè)öï i: °  Úéö¥öiòþßRØÔã§õ"e èHÜ-»:õNõñÜæºé~õÞþ, ‚ XÇZûþˆþ_ôuðõüÍf G¡r äŠØñ4éïé5ëñBþÝ i¸¥JÃGÄ.Àëhä%ßòÛŽç¯R,ë) ˆÚûçñuõ­÷êléËÿÆ[ÙÕÎ*ö¬ä—àÀäõä7éª($¹3S//'PÐûmñ‚íAäóÙÓ`ΣԼäŸ]()BGPJc.'höÔÆâÂ¥ÁÑËà.ø]\+}67Ð0·&ŒcZéÕ Ä)ÂÕk𓛟)°%fã.(øõsé¯ÞØÇÜÜë^ý ‘çWñý’úÝúøÿñòîžò‘úúª  ¢ õrõÖê*î_òöRÔ7ã @Áùbûþ;ï…ààߪÜfí` ú ()a,(*g'êúïåÙ‘ÎÆIζçÛ "Ã,Ú0œ(Š"xõ´ð•â]ÑMÍnÙ»ê¹ô%‰)Ô¼´ x÷ËðŠèÓèlõf™fÅdqö¾PöLê²çúáäá˜ð@Â1mAÇ6KGê€ÖÒÙ¯ÔåÌêØ ó@ „²80IÉA¿0†.ôfÒSÈ÷Á„¹þÇùç«Á™(c=©?O3k$ýøäÚÑ}½Î¼,Ñ]ìPzÅ6õA}9'Ø÷åZÖ¸ÌÍiÓ×àö± z!Q7l?¹:f'ϧëXÒ¾¾Ïmãñø™Ð%Ü)X)ä+¯#§ •øÜíjß*Ó"Ñm×Fã¼÷O %),¤0ç.éþï«ÞÿËËÎãåò)ý‚ åÅÛ"Þ¶ÌõœârÕ,ÝHíI÷|H“ ÕíÐù^÷3òLèKë8úšÅa½~n `Cöí2ì‘é§ä«èøÌá 6%ƒ") ‘ ÿ8ä¼ÕÇÅ“Ø`ðå›Þ\#Ô%'*~ë>ô(Ý©À̼ËôßÅû#˜"©'”."1Ž$ (ú;ðÓß÷ØéÝßäeóÃŽ9 Ž0†-ÙŽî½ÞJÝáêËùôþÈÈ«ÔM2 éÿ¾é›Þðå5öR\n ¾‰ x6€ |²÷rçâîÂýÇ×È"a«Û’Jú©áÓÕÞÑñÊŬǂ—À ( !·ö/Ü×$ç÷ ,‡¼”þÀßû®êžØÉÙŒë‹ü˜;²g& Ì͈ ζçïÁáMàÖæÁðZÿ÷Ú w3ÀÉÖÏúî?âißÞÇÜXâhô Fë#:3<4*'K ÿ›á+ÓáÊÂÀJÃî×uò Ï4òAîDxAk-x nïãÐ ¶Ô³1à ÙròG_(/5:Ú<à1;éìYÙŠÒRÜ®äWéãø8 q3%j7ø/iû´ä¾ÔgÓ9äÙ÷>ýë¦ › Ú_Yë ‹Ÿô ÛÇÐæÚ€ïÑü°wb*r%¯!T ú–ê¡ÒÈÙ×>òòU߯å*%-+8 òþžÝ¡½Õ¾ÏØZñå™ç½ ô+;/’&E“ •õVÚ²Ñq×ÃÞêú  ZÈ*â&ÝF^ÏñAénñ‰öóEõNõ¢ò#ùùÙ RµÁþÿjõÉö>þåÆíŸûÎôUóï¶ñ4ûfþ<þÌç ƒ æÆÿXÀþy³õ,ì1íÙéªåoí±ü“ ì7BŸ¶ýŸøîí ëÈêœâ6á~ïþ Äh#ô'Ô”ƒ 'òáÙXÒÐÔÒåüù’žƒ Q-·3\1 %[ ðÈ×ÏʼnÀèÎáãóß x1:HœI34KxóÅËæ¶dÃ\Ú\åÙì%úÍo+Õ>7´'¨ô×Þrã÷ò/ôlïõ÷˜÷£«j…}þŸò3é"÷=ü!cyÿî*ñ ýÈþIú_ó–âRÕ¤â"½éoJ ÷ Ë©ïŽäªÔ.ÊÙŠõè dÂûešA +ÿTá@ÂEÄWÝb÷n ÝxA˜†Â+ 7÷(âœÞóäÞë÷?$ ¹ß¹¸ RûÞïþòOü´ }þ²õùúþ7àû ôùû§ ý  8Yÿ*ú0÷aëÜäê[êõètöÓ Àfî²[üÌ ÷µá÷ØîÏ5ÊÒÝ÷M‡À”§°©…!ñÉÚàÂ~ÄþßOý ",'J!ˆÓ‘w?û5éøÔ ÐnàÛò6ýÎ Èa k$Í(­Š'ùÕå€Î…ËçÝ ôße ÛÁjÎÅ‚/úÜàÑrÚOðý¤ª+ éXþ‡ûÆöFì«èmóß" ô ÜV\š$ ²ò0âÕ.ÌjÑèH ´$@.…0E*6¹7Aõáߡв¿Žá’ö,Í9-EµEH4i¿âGÆš½,ƲÑáB󵑉'“ ¼ÿÿðøÒuɓܸ€7"Ò)y9 5 þÃñÑôTöpäßÚÕè2úíI¼!B~ 0óïò¬ïûÞÓٹ꿎 Õ%Ó!qì ¬÷’ì&é®Ü(ÖFã5ú¹êû";(3°vñ¨è/Ü‹ÎcÖûïx c¥ "džå :ümî;Ý@ÔÜ%ì/ÿþ@E … çþιðçÜ(Ì|Îðß(öq ›O±¢&ã—üiñTá¢ÕÆØ'çQøÉ1[Ù£Áúœð„ÚPØqèV÷‘£vËÒþPZÜ íRÍ÷àná ò¦ƒƒ1(ó ì0ñ¦óýú ÷ Rùým ŸC5‚Œýèîûë}åÉâíNî×âíîïo,×0Q0]*!ñõèô†ñáäŽäGàÍxͯëVŠ&(4’:É-¬ WÁñôì’î÷ÙÒÉ«ÜqùŸi[à›äŒ2 î‚ø—ãwÚßæ~ùXW»ÖŠ÷ üÓ 7ŽøKïöYm oü=ïrëî:î”óüü¡ýúu#í$Ç „ùÐí ßLÖ•Ú=âààžäèûy2J<92n ýk œûçÞ×Åð¿›ÚêúÎ)‡7È.¯"ÿ!®ž}ù“õܹÄIΖæûˆ •ÿøÀoË – ¤÷Íàˆäöw™ û×øFü$úãõ|üËúHèÿã¡ùZD%ö*ï%Óúñèìžãã¤êrâg×Èåé³ú2¨>Ó6޲AõÌäœÚQá²á„ѧӠï÷  %Ç6Ë$|;cCì/ÅwÖ÷<ïñxöÎåpͧÒ;ðS #?õ?r"ä ýVãQÙSâ>àtØŠäöü‡]4,Š+ ·žõKâàÜÖâÉwÕ_ùô6-6i3É Sü|èÜÜ¢ß>یΔÐùéá ¸"1Ð:1.ÈI.ñ¶ß@ØéÌÅŠÏæs'^3ø6ý.zN _ÿ¯ìáüÚýÌqÊSÝü6I2I4š1m&|FÓðé2äZÕÚÊK×”ö$[-b4â0 &7ôÃñ–êrâ¡ÒÏ•ÝhóÆ $Š1ä5†. € Ôô¶ãÛ7ÏUÈfÑèép(P.O-&¨þì“å€×JÆÿÈÒáz-$j2ø3‡(Dêó³í–ïãYÍÊÜoø>)B5Q1(CÅøôGÞòÇÐÊÜåñ< Q"ðŒ 2û ¶ ÕøÉÝ¯Ò Ø6èÒÅÏ!àASüZýï | ö?ç½ìUúª fmå îþñôé ç+ôaúàê\äUòê"}$Ö.£!¬ #eûäë­êrïeßìÐ ÞMóÕ w+™=E3¶m’éówíõû^ñ×ÒÐ åùr(n.Ð!½ü¬ýïóîüdôÆÛöÚóíg÷dÿÏ ýz ¼””úwÖýúå;ÜAð°) vÃØ~ø´üöù¦ò‡ÿr }û¤í“õ ˜¯g¤Hý’ïäˆÝ’èÚõ5÷·øw—J#„; ûôí0Þ‘ÚïßWß®áôé%*61Å6B2¥§vó¤äTÝà„Ý)×8àˆ÷Ê -3u)Ä €øñëoà/ÕHÚé6÷ ~ znвgÄuó5à4Ôבâ*ò%Á Ìz#tØù é~÷ç ÝÀÙ_ÖTÙàêÕ6o8¯<ì1ã#pçý—ì$ä„à§ÕIÅYȤß#æ'qA¼BS9).×LùÚê-è—ÔrÃ4ϬèJÿ’ )·(mÇp >þëòÑï>áEÏMÒÜìÙ¥4EÞ7:rþÊíü×=ѦܑÝlÓ\Ödê¡ ©/ÈJ8SÚ=]Oü~ÙàÃSâÁ6»qÉëW¤2#KVuGr*Áû|ÝÍÏÅo²›²£Ï ùÿ&®MYaâRh1rü.àKÜôÞÊ´²‰¾à0)ÕNX-Dõ-² Ôã€Ø'Ù“Æ~¾Õ&ðñã54q9&óV)û"å#ã»ÓmÁ»ÏÚî7‘1 Hï?†!– 9õEÖ^ÉìÚ6àñÒ×Ròn&'6BNUIIª)aÓÜ·;´'µ¹/Õƒú9/BQ ·,·*f!Kôóë‡àÚøÕÞÛ†ðíÀÞ.ê/H+ì#üGÿ½ñ»ÜiϒѧÜdðÑ\Ä@!|ú ¯ÿT½ô‘äè/ñ×õxúª¿ dýü\ôôð®éçlüÙï›/bl¥ÿôÔè~æïàõÚ˜èzüç T"Q/@+ç!Üß äð áFáWÚJʽÔäðÓÜH$¥.†8÷,¯ öõ¡ê5Ö ÂÝÌèŸ÷鳨5Ð!û&5Á ïðÖÉÑgâÏòcþã ¤G Óä üýüý°óžîxøßue쟔ÿ°ÿ)öïbóóæ·çärE!ípt MÿÜúî6Þ•ÚèÙ_ÕµÙ•ðÒ œr0â@W8ß!‘éÿâÞѰÐ]ÇYÀ&Øïû+É-“181#=¶37 &ôqæÈg¶QÉ\çáüJB%¿+›"ï"ÿ&F£‚üÖä¢ÎÐ΄ÞRñu„ áZ!K$R¾Oõêxܱ×Gã¶÷s~~¯í JýSï¹à!ÕùÖàë;G;,*ß}íþiöçÎàä°à)Üé.tO)s1j'ÎSÍí¦ÖÎÙτ̊Ï÷ê€Å/„<é>~1¨;Ûú>ä˜ÌÙ¾¹‰½Ö„þS%ÚAöTR>9+« bñVݪÂÕ²¶¿¥Ü¶ø©O-µ;6\,§$¬äöðæÞÿÊÊ­Þëû&¡% *øàÆž¢óïè„ßeÕuØëìŒY¢(ÿ+Sµ%sê Ý—Û'Ó”ÇÍÐýëŽ ó%ä4.<¢1:ýEû¸ß2Íé½ç±©¼ÜÓä$r=íG%B©2Ì&Pì‰Ú•ÍL³B¨vÀÜçQt3¦E|Eo<³6ì!éòºâáÁ³FǾã®ùšC0d91Ÿ,‹"ó 6øóê^Ó«¿ÇúáÖý-s-L4ä)L#âcÂñÎçøÕvÆ’Ï‹è.ÿ!9"=.*à#+@ @÷í˜ÛKÇ·Ì*é`[&áø~ÜñQíñå Ù¹Üb÷m ÿ DC%±#ÛŸì·ÜµÔÏhͺÜüüñ?$d)ü/W-K%:ùÚÇR»Ê³DÁšä÷F#27B?…e-– ìÕښdž±°4Æí?)O4w=0B‚<'!VðwÕU»‹ÂÉ×Ùì‹$ê+_/,-.¹ÇïÞÙìÀ|ÄÞxø¶M#Ì#HÛ"'Òúüå9ͤ·¿PÞûRu&@,É*s.)SFøxèiÓÒ´¹¯\Í&î½ ÷%Ø5Ì8&>G:!{LëÉ̺±àµœÖò†Ê(4*j4MAã3ïÓöÌÖ‡¸£¶ØÔö  Þ#U*½ä°) © ùÃâäÄUÁwÜÒõº‘”)Ï(ô)(~“üçëõÔXº.»WÚ¯ù 7*Ý&2%Ý.,%å ò™Ëù¨]©Ë®ï~ï r3Y10-«."ÈDöùãÂd¬ º­Ü)ü´¨,v76?ÙD(3 «üÞØµ±oÌ¿ëbF‘Ë%'*Ï5‹6Í" ê?Ƹ ÉéæGõ\#PGß$$r°‡ðÔ8ÆëÔyî³þß ‘p !À#γ &û•å¬È|¿”Òñé£}ßö„„š eü=á0¼V°‡ÆÝçÌw"o(Å+«. #£ üðéËŠ´Ë¾¼Üöúr.—",w6„/~cýõ²Î¬ºÑÇá÷¼ Äà)#ƒ.-ʘ ýèÜŽÈ5Îââ’ùaìg¨Z!Œ&'J ©ãaÆýÈSÞ óï˘@D“ ¿  ðÿÔ Õãåï½û M …h Ä ZIåóÎb×ìsÿ¬V,Å U ª XÇþÿ¾ì¶ÏLÍÚã0û:á(«*"?!O)‚þžû[â¼È_ΔãððªÑñ#’o(È0. ¹ :›åòƸÆkÛ’ìÖÿVÔþ#fm¼ ü,ØÑÌÇÜ êÉõ gÞ#Ým Ïëå4àëzò¡õ¿ášuLg¸ ò$à›ã9õ†ÑçýÞª ûü€ôç÷ÇðÛ¬Òìâêý M'/þ&å"lèÅöƒøHçÌKÉ7Ý+ïŸú\Í%à&ï*.5ä'htÀëëÑpÊS×_ç…ôäênŽ2(d)j“ÿ írØ«Ö'ÝnçYöà ÒuŒíÛGð³éºæÔèöï÷üE8d´Ñ ¥üxúw÷¬ù0ÿWUþ‹ýþðÿ¯ü«ø¦÷ø$ò¨ñóÿ¡ û æ y ªeùrí`ä¨ÛmÔMÜøðý`!¹!Y“é×)÷}ëáÑÈ’Õ?îãT´,….j6H4ËdøŒäRÐØÌ¸Û¯èqï^þÏØI)¸6Ð.R;=öZÞØã ïHø°æ©þs­€”%Ï 6üìðò­øÝûÄþ Cl Êö×ñ6÷«÷×ñRöé…õ Ûm œ …W¼ü{ðõéÝÃÑßÎø© [O ì$èK*@ÿNñÍé§áŒÖ9ÓKÜÜïüœŽ&(+Ê/W.7 þ‰ñîÝÕÌÜÒgåóñ%ø Î ¾#ë1‚), ƒònÙ{ÛgéŠò/ú¶F°ÿ£x vŽ v ÂJüøøÉú»þûŽÿ&ýXþhüEø¡õññbìäìƒóÍýV(!]"7ñwùûÙõÊðŒäf×]Ñ×Ϩ×ÒöŸS4:3¿&™¡^ï4ÜaԼŢ¹Ì2ïë *.r46î7]-ü-ùvåþË»BÏñ€ý(ü NÔå!È2Æ)ȧ4í÷ÚâäUüA^i•ûÆït÷°ð¹ Ÿ§ñ˜ú¯B$êk ýÑï îuê~ÜõרãÔæoåÆ0-ã8Q.­'oÏ ùgðÅÜ’Îǹ¼åÀaä…˜3š;®<>3Å"M¬3ùŒÞbÍzº±‹ÃZél |!…/>7 7ã5ä*Å¥ø£ä¬Ë ÀXÒIïéÿjÍ û xÄ)¢!‰ #øÊãžÚ"벌k ÖÍø§ï‘ö°ÿÔþ'ø”îºüEZ(ÛgŸÞöêò5êÏÞoÛ^ÝîÜ#å½>(5e1N)­ Ó ùÝçž×¢ÈD¹e½øÞvA(z<3@84“%RP,üâèn×\Âò·VÆŒáÇÿXþ.Ø2¬3Ú4~*.°ÿÝïìÖÄ$ͯã£ö°ê„åË!†ÇÊëYØ›âË÷i]-þâ÷KúîõUõ“ûAø‘ï©òæýî `"†,ê¾¾ýHósß§×:Ú)ÕéÒˆæO\*4-9ù0%"+ î(ڳЦ¾ÿ±UÅ“êØ æ/G E82$¾bó çNÐ’¹ÿ»nÒƒîçŠ,î0G.34…2"ºÿ~öÁÞžÇcÏèàú ¨I%ò"¤µíÎçÌÓØàšû¬u$°ÿ¨ôtøhóeîñÈë]áè ûÜ v#ƒ0ú'¡ÇúKååÖÖgѤÍߨÿ¿Â/T4´-¶ù ùôwåºÚáÅ·—Æ1êÌÿ-y@"?O,•ÏóSçéÐÍÁ(ÈäÙ1ô‘®.Ü6´0›*Î#í ©ñZæÔªÃÝÎSèþig%Ä)c"H %ewöÜÇÀ ÇüãküZÜ(},–×YmÏhý)ñ;נжåqüO< Á&î ðpýò$ð¾îçâôß)òâ©ô'ñ(|¿Nû,ñßÎÚñÚIÏÒðß-£@Õ>C/‚ õ¤Ù€ËÌIJ¦®dÐ]ýÁ'L9W N¡:/#¾ 7ó¤ÜÑʰä¤å½oá 8+)D F=?ˆ:Ð.`÷Ôætɱ]¿à üS¼+?)ÄIÊ#|² &ÿœß|ÂÌ~ë ‰*&ÔüûZñ‚ëvð,è‹Ø)àNøt ."02(‹SøâæèÙ›×€ÎBÅ×õúÊR9pDs:>%;A>ëÚßԳó®üºvá­ 7—RWáFA-\TúñâÆÕÈÁW¯àº½Øƒ÷Ôˆ;FÆB';2}÷úì¾Õ"¶ï¶[Ô®ð¿,¥7¹*祽Où ç©ÉÀÃYÝ)ùH)-2'c° ăí<âÞÈÏÃÇÊ×þômê0ÿ>=5–$‰ ¦ùLèŸØaÁ–³TÃ⢂%ä;˜=†4»0~,-‚ùyæôÎ^´¶Ô¬óÚý'#-àï#(#Wh üñιÅÜÛ=÷Ç D ¶$ÀMÿ8óï§ëMßâÝ8ï…0Ã0ÑJÇý:ðÞ’ÖùÏ–ÄÈÉaç› ç/tF)Dn0pN û%å_×ìÊYµ;°®ÊÀñÏÏ?,Q€K›:)z¢ýŸæ˜ÎÀ³Î©H½GÝšé+¸@?8á6s-!døhå,ǵĎޒúq£0Ý-^ €ì!{«"ùcÚ×ÃWÑ"íËöó&œ"±2 g T‘õKíjÞÒÛÛjñûÉ!2ÿ)“ܧÈòÙã¢ÝQÐÈÆO×±õ›4=ä.U? BùÊãc×jŨ±D»oàÖ©0·JQIæ80&jijïêÝMȱ±±l̦ïžþ;ÆCP<ð5Ø0€ ûë(Òï¶é®CÃÌå *#5j-'¼+"*O{Nì[ËL¹AîÞ2“r&}!Rž;2+ ü”á(ËšÍîå‡ !…« ÙppANøÍëÝùÙNè¨ù9%:å ©ýƒø ï£åDÛáÒšØÒïÌÚ3õ5 '”iqßø$î•á/ÒùÀ\¾ÔÙÝ3IÏEt6"aùsñ•Ü*Ë%¼i¶ÞÈ@ïä75(=ù4´0€3¥)Áýõ©Û²½ ®Æ»ùá} ö ¼%z!Á8"r*Ó"qéúÙlÂ/Èvä&Û7¶û U * yãúïºß Þ·òÆÍÑ ãøoù»ø«ïPçGá½ØÏÝ»úa!Õ6ö0}$lN…ûËô²ãÖˆÍ|Á*Æšè÷J?©Fç?;3Øë ¶òœ×—ÆÃ¸!µb˃ö ”6—=W;u5ô0À#ÿ8ïeÜ]ÇŠº~Êî½ OàÃKô%1+ kºîëÔņÔã÷£d¾Ï»Œ ›pâõüãÒÒ³Ú;ûƒÉëV oËþkIÒùhùçðíßãÅgÃRM <<ÿþOõ¬è‹ë+éƒáÓõ#U0½%¯6ùõÅñö¸ïå^ãÂÚÌÕÛ \3š>b93,F$Fÿýì#Ù`ÖNЃÁÎl÷Ÿ)A0º1P+®)z&2 îÝ+Ìw» Ç˜í• ±¢l4â+ë"d Óþ:êEÎγìFç Ò [ ¯¢Q¾Ã®ÿŸè}áþúüIˆ ÿ¥÷Îùeò-æ<ì/ônìêòÙ“,ú&l]€qûAÿ ô;Þ(Ù7×¾ÌÚÕ»ñ.¸@9;0É/ Ú þæÝ®×©Â¡½ÎÛzˆá(­6M7á/-å‡óñà•×TÇ-Êþèxî › \ò%ö,Ÿžñ×Ó‘ËÏè6 öþ#ãú›˜3ûlû]û¥ìåáò ¾Ë® ×¶ ðŒêcèEÜßÌù…×' ã §.ˆ$ûlðÛØ<Ó—ì, 0—i¿ÿ™åãäF Üø8ðøªÿWžïåü˜ï7çÑívõ$ô”ýó2  áþ[ÿÆGò2åýÛHÎTÑ»ð¤Ù+Š2Ù,P¡øKì@îáðâjք߯ï|ÿ‡N¾&U'J*ÍÐûÇëoäãÖ5Ü(ö2iµ>¨Ês<%h¡ §þdâôÑ]äÿé :Á®`ÿë 2ݱ\þ1ô,û€4ã‘ÇÿAÿèð;ìñîÖè&êènf æ ÿ©÷|üÖ2÷Öë†ç„ÛäÏêã®Z! ,)*r ätüï(ê.íhåÜ× Þ—õ^ñ÷ß#&J°Dê+æ|ÞØéõ x ²Fº ;!®ŸûÙêUÓ|ÓRëoܪäÃò êÿ”ý½öhè_çôˆýHP_ b F<aþÍõ¥äúáYô‹¹ ‰   D.> ÒzGÿðð éqîø'þÓß\ « ‘ ¾õfð¿ðTíœð1ÿq k O w¤ü˜ü‘Y öìößÖã¹–!( &jµ RÐù·ñqï¢ð<ëjß¡ÞpîV{ŽG& *ó*C$­ vîuáÕ[λÚò𣵠ó¾ŽoÊ+j(s ôÃÔxÌïß„÷¹*|« t ³}N > Eû÷ŠðÕôxú‡ûpü9 Å—þ9öÛö÷Nð¯ó§¡, Œîpüdþôý.ó‰ì"ë­ÞùÙ5ñ$‹ ¯$sðbiûðêvæÚÊÐOÛðR5$m-¡,€* ¨wñÛåhÖ¶ÐàÞï˜øÕÿáÍ KŽÞ-&néŒé•Ò›×øï÷Çî Ò¿æã„ePúåêå9ðmýø‰Mf¼}˜ øð ç¶Ü%ßšï)ÿ# | ­Œ ÒÐ¥åô“ÚˆÐâ`úoÕ £ šm ›Â6% ëúzêÃêPóyø"ÿ *),ïþøGö1ø'ó€ò,ÿ} 2jùþ‹.WøåíçêpÞ`Ö4é4>o"="Ô"ª)þÓö|ð€ëßcÐ_Öìpÿ23])R+Ä(¥9 ÷Wè ÙëѼÚwê÷[² ó—Á—-“%ûùþ¦ä+Ð×ïG¡ õ•ñ1Þž eñÙé_ï9öMú€ ˼#ƒÿ‘û±ûÅùfööûoÆ Åý`øÝþâÚ"øÍí[æ|Ú,ÝÍù Š,[-'!(zÙüŒöó*óñî"ßDÔÀâÅúY 9G'*)'=¥ý†ïŽãg×Ó¼ß óoÍD]ˆ~%+ñ ìüÌâ Ï£Ò¤æ†ø| I€ Ð÷Ìïê“Ýaähò@ûHD›?ƒØŠ Ø •cû_í…ìŠô–ø‰üýÇ 4hÿæû^ú‰þrü­õ‹ø8VCì¿þ_| d”ô<ñ­è$ÞŽåtü×*W %Y ÅÿgýMú¹ôŽô íxÚ ×1çiý• ÆE(÷,«)s! ¬ó@åÜÕ Ølåêókÿ`þ…Y.d+Ä„ ¬ô×àÎCßdòòü¤›† ·o<l€ œü5ðYñÏö*øÞúâÿ)ŵãÿxÿ«ÿºøö«ÿê çé#XioIõ¿ñ¤î-âÏâ3÷ù fdÑõ¨ "~üù›ôÄìi֣̇ßý÷‘ @"Æ&ø&$›Ë÷:îÁÞIÓ|Û«êïóËýÙ XÙ"')TnºØåÕЊØJíæûU[ 3 rÅ   ¸¹—ùÜæãäªîcõ“ül: »jŸFUsõqãåéôUþ«í¦ñZ v ­n 'ÿ6éÖäÝïiù¸Í Ñ ô*h v; ÿUíí ù!ðÎû o7Å÷^øÛèý×¢ß(õÌD¸Ê ” njœ®×élÉùÉvâÎøV  $ÍÊ­ã {1WðÐÔ5Ñ.â¥ítùÛ tU Ÿ0d$\Jí6È<Çýß ó¥ÿ» 9 ûz]Z¼ƒâ=Ù1âí5üÖ ÿ #TÒOví Sþ5çæçŸö› ‰ …¡9ýLÿë¢Ô4Ù³î£XÁ xˆ à^õVæðÄûÄØÝ™÷GZ"ø%‘ '{%¦Ò¾CìˆÐ.ÍÛ¾é:û) 9¶$Ò1A"á”ïõζÐäiô•† ¾ 8×,3ß¼máïÒCÙSçúÜ Ça‡×Bä þ`ãûÒ]ØÖè¤÷$Œ Ï _þÌä' Øì@Ðáͦà0ö…"(Ù¼>Ⱦåõ¹Õ'ÍgÜöó|üÓ Ñ š (òÓÇÍß9ø1 Âȵ;S W¡üÑáXÂ)À×iøadib ™ <þ™¹î}Á¤®ã¾Fàä”j$%(¿,¿.$†ƒõëγÀËøß`øˆ « Oâ,S0Ô'M1þ²ÐT¼HÊ€æÔþ'¹OXä ±W”ãÎ’Ò å(÷ãFîÉCÁ þ ²÷3ØÆËz×VðDÏøÿζ† Ÿë.ÊŒ¼éËéG:X!W#%W!5Õ ôð/É=®—¸Ùòú6!.#z)È1 -2#)eýUÕýº ¾>Ô‚ï BëÞ)¶1î* ‹®Ù>¹|¼`Øgøà HUÏe³"h!{f`ãÂ~¼XÑñ´q4 ¾$u'Í#5àÀãâÃ7¿HЇë¥Ê Ec"Ó(ó-z'íñÂÊ¿|ÐFî\ô¹Wïv$b¶ KòˆÔMÇØÒoío JcЂç[ëÃÏWÆhÒïs_4Ûµÿàé~ÄÔ²Áã²;]! %p*+¹!«òoɹª-²Ôsöç ã' O)û5M9Ž0]úêÏ|´µ¸×Rõ¦yóVË#1Ñ.7# åâ¿Ô»€Øø×04¾](‡(dÁEãÃo¿mÚÖø®IìX"ENKÐýÙá^ÆiéÝÌþc ¯¢ €š4!•H uö’Õt·RµÒ‰úP €&¦'Å$Ú+{,› ä—¹M§Ÿ¹àà•F!Þ*,/8œ8Ó)Èé_Þ²œ¾Üœ÷ „H%$F/ß7/©¶û±Òظª¿Ú»ó½ù[+"‰/ß.É.âÅDĀ݆øJU–˜ IÜÔ"ûÅéÞϰÉÜböz ÚaÆ\_Ç ¼øˆÝÄÁýÖù‚ KŸ#ù%ð3'ßE»ã°ûÇ&íf 7Í"Õ%'$/ã-ïäæÔ»c¦àºá¿Š¨ý$ÿ*â9ô>š/Ì+ñ’È|¯º2Ú¢ò蕈wÜ)47Ú-OÖþ™Øn¼AÅFæSÿ¥ Þ¹ ö+»!.üTÛC›Éàçhþ ¦!Ü9µ-@ïzÔÁšÌFíÂ{Ú^ Þ6 $*LÙtéLÅŒ¬Ñ¹ àz&0I)Ç*Ø0à%ò­Ìשº¨šÉïÝx*5-7lF–<„Cü¾Ó ´N²'Ëuç÷úì ñ¼!¼454‰¦¡áõ¿ ¼ê×Àõõ`è±!+(ø§þàŒÀ­»ÕÕ°óqéVÈ]'&4,½öö§Õ¹ø¸cÖ¼ô{ ç"5u1ldçvÇ ÁyÚ‘÷Z¬¼P ¹+#9%ãîdÓOÏðå[ÿÞN/†3ôÛòñ÷þäñÎ]̘á|ûΘ ieï+(ˆàôÖ€º†»Ù°úP ÕÓVŸ%ô%⨔ê²Éj¹È–åÓûJ ¡­#³)Ó8a7i!FàäDȪÀòѤé$øˆ $fP)n6Õ(5û‰ØçÇ&Öï"ÿ ßDï ä[\®þPíùÛ¸×çnüíûõÐ-f÷ƒ ãùeè@ÔÍnÜ ÷Í "¿¶Û$ (‹?ùÝÁ»Ó…ò‰ƒúAe.W3é$Ëë}ÅK«.¶@ÖÃñÞ¦$5+™< A÷* î²Ï¿YͯçDöLÿ¼ ¾Âw&£5`(Ì{ú ÚÂÔÊyæaû· 'Â{$Ô. 14ð¸ÕÈÔìGûtÀ Šž3"ç1®%œ÷¬ÙÖÄηêóÿ cÈ£ R² . ZúíæÁÙ&à ô€zŸsÌÝ$ts÷ÞÊ0Ä)ÔÚó& sšüé‘),ü‰zæQÄy´ÈÃáãúþFr"q#j.„2í j×ì Ï›¶Éº”ÖGñ,vËó!6òD³3]†öÑÖݼBÄÐàó0ü"á 0 Ê#,:&1ežåæÈÌŒÑ3îr³ í¥æÕU„*ø?æ’Ùã-÷®½Ó¨®@#&¡‘ðÜmÇ6¿ÞÒ3ói ƒš=ZV&0)r|æ/ÁO­0¾oàÌüf*+%È$`0¸7Â%× ð¡Ñœµ ¹ÿÔŸî¿ÿ·g2 4÷@d.ä£ñ-ԧ«̡åùÃá ³ Å6#Î3â'j)ø?Ù)Â6ËlçÿRV×!º(’nóó«ÜɤÌÎâ§ö^5B{a,i6k%HqîýÖÆ ÎGé‚üäd Ë k  R3x*sÈã?ÉÜ͆ê:-½[ã XR!à\ô¿à~Ó©Þëõ€ž c¸ ù&’øáçÈ‚¾‚Ð8𦦡¼"º*<ÿ¬ãÃ^±•Âèã[ýL U!7"/J6&É ™îÍ`²…·~Ôìï)¾åU"m6?"*ï ïSÒÔÃÞÐÀé/û9¬ d aŒ$–4°&1nùvÙÆyÔðÐ~ìýa˜ãxó²â+Ú‘åœ÷ çöðË# %‘åñM×›ÂÀÖÔàöbR p´-§.u²üÙå¸+®~ÃåÃÿKG þ"T+Æ:Ê6 „éGɾµ¤ÂœÞ_ö =ÌO#b8î9×!—íXҦ ϕæÇ÷µj‡°F4;S% tô»Ô(§Іë¿þ' •© È% +¸OöÌÞ}ÐÉÝ~ô%Ä‘º—3põÏéù×OÑRàÝò4 ¢‰•"I+‰þLãÑÀï¿bÖGô Êæ3‘1K0ÓªùŽ×6´#ª3Á'âkÿˆ§&Ý*3=c1Aø²âDÅù´ÙÂÊÛ¯òž[ßm)A>Ò!m¡êÏ ÆlÕëEüy}à CÙ*ï*× ïsÓûËìà÷ú{IÕ¶´a %û]èfÓæÐ:ãõT&ÖÖ&/Ñ8ü³à”ʵ¾FÉðã1ú(nÐ!Ú4Þ.ÞöVÐz¯û¬3Èséß>8+t,­3ô7:)”iúÏãǼ»ÃÍ7æ0øµc@r,–E{=jãýNÝc„ÀÞ׿ò^fø;/ƒ,Q2í)ÐXÄ~ÔÍëbQØ#;!N+5" »øæÄÒÆÊFÓÈâøSþBw)¤7è,ªŠô=àCÍçÆ ÐÃâ ø« ýaa/ó/øsdóÚÏÉ#ÏÊäåüát°’-·ÿôKïQèrâ2ä§ìµÿH½Y$æ.¸1„±ú#܇˴Á[÷Ô+ïÃË$¼%÷ Ÿ(¯4·0ÓˆûÝ™¾‰ªÛ°‡Ìšñ(¯*46Ä?MA2Ö:ü²ëÕØˆÁɸAÆ~Þhù¿Þ.KDCÑ&? ÛòTÚ Ë*ÎXàíönކ èú!Æ·ÿøíaÚ¹ÖKä†þÜœ´æ aqï„æ-ÝãÕÉÙÚäXøÚ×z#l+|1ð"Ñáä©ÔÌÇ|Á˜Ê‰ß’þG^"ö!Ö)€6Ü2:âøOßOÆÌ´ª¹RÑÆòv‚%X,(3î6{-Z‚ÿ¬ó“ãÊr¿MÊHà¡üØ@@.)Bo@”#œêµÔÇÓÊWÛ“òå$)/û#57ú‰âÃÊÁ<Í”èºmÐ&:,/.f&ÞôôMëÐޯЖËÙyô~ ®R-¯8G4wàðéãAÜ·Ò?Ñ£äjþ† À–n!Åx Tc÷§ê†Ô£Ê•á|â&\,’  ó"éÓì¢íúÞÖÍäòþH1%Ø8M8Ñ"¼AëÍÕýÒÊÔîÎÓ:ëã )›)¥4ù4X'p[^è—×ìÊ=ºÍ¹èÕ0i"¶7oEAL-¸V¬ñ±ç~Ý4Ƈ¶ŽÃ×å! …"0;êIFBt-X‡õUåÛáÌýÈdÚ’ôòˆÈT%¿!©ßo þýúî¬ÖâÊ«ÝýÚ ("M~èøEï‰ï ñè·ß’í´ö;„+^)©‡èØ%Õ5ÓÕÐyÙŽð¯Õ&?/ø6Ï3{%ÄÒù#ßÌÍäÀ-µ ºÖÖXÿË"¶9íFdF29Ž$ öæÖ­¼¼¬]»òß$Î;^G @ê+žüUíÄãáÒ=ÄoÏÆéú+Ž)ú.æ%V˜ëÂùÉñÿÞ[È¿ÊNä¦ÿùç15d#K¥ ý»õDöféWÔ®Ó æãøÖ q%²+«³ ýÿúõðAÛ½Öýè±}(.+'› }ûøÇó‡ó\û¶ô©à]ÞðîªÿÉ7Ò5*òâ¢ÚöàuàØØëáöÏ *÷??:,"( ïpßà×+Ì,¿Ç/å- 5NªH§/K fùôì8é×q¹[°ïÇ*ìI?YJÿ7&ðpÃûËøèZÏûÉÙ_î81ì!^–ý x ^ú«à×Sã¯ü8-\!ŠòñîUîØó\ÿxúuç;âLîË"9}3è4ý?é ÚÎÕ„Û<Üh×àÕõ¤2I˜Cö&Ù sú…ëU߈×vÊG¼JÁiÝ6°2 R–PZ7R6fÿ™òãìÅÛÚ¾n´ Ç€è‚6§*ê.V'Ê+³3K'¦ ïË¥²÷·!Ôûñï ,%ó,T(n2>>=,q ‚ìªÌú´†¼eÙ>ñÉXíÄ2B¹/ ðùÍ|´ ¸JÑŽì0k\!!J+=6ÿ*¤…ú§Ú–À+¿2ÐçWen"#,Å6(à 7õjÝÅüÁÇÒ´èÿ­Ç!'# -…:ê)m =òãØÓ¿ø½©Ï*æÚþ›û¨ *J5(( £öOÝì½ÎÉÜDõ¸Ð!¾'…1h6ä#g‘ïÝ~ÅwÀÑÁæ¾ý;° œ.¹!?¶èº×<ÎPÆÝÄåÖ÷Î#N/²9.8'üýÙêÛ©ÍÇÈÜ‚ý:à"ï0ü4œ)§ó¨êä¿ØáÏ±ÛØø)E'«8ë9Š(GUóÛÕH×OÓVÔ(æÉÿWn$ó5í?w6öÙõ}ÙnË’ÄW¿yÃìØáý}/_AÆGi9¤oýìåºÕÏÆ»9º½Ê5ìì) ?íR¢N]3fPñ‚Ø‹Ê]À¸üÂåH ¦6àHNEi1Kvÿ{êŽÛQÍ$ÂpɃä¾920ÈAg<Ö(ò9 ñKæ€ÖçÆz̘æ“_¿/Ê<Ä/G& "ø×íTí}ä`Ò‘Ð7åÝü+†/h>ú0gOøìùÝlá”àuÔÖOêáÿɨ'‰8È59$ô ÕíªßæÚ‚φÇDÑêiÃ/æ7å,:xn÷NëãbÕKÆÈáà¹Kc55Ež= #LðïøÞœßß<ÏµÊøà5v+’9ü6t&ôˆÿ<î^åÝ٠˴μè®d)2è=,-¶´cóøè4ë¹åÊÑqÌPãEÿ) 7nGÕ5HouçùÔŒÙßÚ«ÎOÒFëòÂÇ1{C[?±&)ÜædÔ¥ÓaÎwÃÉ©âÏ› ±9æJžDu,ËAø}áwѳÃH·º—ÓBûdP8¤QƒUÁ=hJê"ÞÆÕ Â–·zÉœìî 2#Ä“*}ü²ë–ÛÀÊDÉØÛÈö× »î/¯0X!ewšõùï“élØfÌèÖvï y#u8K;!-jý)ç ÞàãÚÑ©ØqòR ]K,ž4Ô,«ãÊöÿë•ä|ØÎ͘ØHõÊ·!Ð36ÿ! cýî:éâíäå ÔôÖð= þ$w?û?$%" ÍôÛÕˆÞÚEÐ}ܶ÷!$o;ÿFÜ8¡µúÜ—ÐÓEÊæÁçІñ÷C+&B†I8plóîâœ×”ÉÁ½ÄÜáÛ)&\@)THJ™*d èì_ÚrÙ0ÔNÅDƉß</¶ByC³3DŸjî‚ÝÙÌÃ^Ï«ì|ˆ»-:æ-ô êúñŒíbàŠÎýÎÅå>…2þ;ö.Ú/ê ßyÞ$Ù‡Ï$×öî3ï'°3o1Mj®èÚÜÓ×TÎȬÒyîs Þ *1o7¿->†©ñæÓ××ÊDÆHÏ9êü ‘%–5D‘?§%øðÀâÈßßÙñËÎþçá.8:ì8)æü;íwߤÑvDzÑlðݧ!p1É:­0F¡¹ïŠä+ãiÛ¶ÍaÑÏëi ƒ!«4a=25@"Ÿ‰ñ™äþÛ^ÐÂÉÒÕ;ò{!3ì=/£>‚ì<äÿäßÜsÏIÓSëÏõ8MA1:µü¥ààÒPÓžÒ'Ñ™ÞG÷ü <Ê.^<å:9'ÂèåâՔʶ¿OÀVÒ òˆ (Y:@£4 Zõ/åÓlÁ÷ºæÇóéLÃ'£9ÑEˆ=­#ƒúñræüâœÓ¯¿ÄÅLäçe?0ê< 9A'\ÿèð¦äîÔÝÉ×·ô’ ûB. 2#Pæòòþòaâ…ÐÃØúñC ˜!¶7z6u!B ±ð'݆Üçá ÜÙëue}+l0B'ÆÑð ßlÜèÖÝËpÍáÈâ0U@&;í$Híÿà.Û{Ò+Ê̲Þÿx³,?dG¼6Øyúoá?Õ„ÑÊBÉÄÞÊ|¦*7Ç9f.Œ’Ìï§âìÓRɒ̓ä…ÞB,«:6ÿ  ³öÅèåâªÛáσ̀Þlþ‘<1IA=Í&Š %ñÉÞ¥ÚÓÙúÏÍÌàeþ¨(.p<Š:u*ßJý¯ìéäÜžÌQÉ5á÷ÿµL/ BD4ž~ 2÷ôê½ï½îÅ×QÊOÜÝølc8[J4HˆþAåKÖ;á俯ØÖ2éHÿõ\.C@Ž(ïÿáÍÏoÌ.ÂÏË4èµ!}<©HP:s"° MùšçtÜß̸˵¦ÐØ÷ÑŠ;ËTcM 0mÁûçä•â@àwÉܼ{Î:íð¾!¬9²;¦.B¡ AúÞïEá’Ìṽã´ü5#'F2 #:9ú{ô£øÛñÚÚ}ÒSãDúég5â>K)ôªü åqÙ”âFäGÙ‹Ü”ï—a«+é:s3i9ê-ÜhÛfÖWËxÑôêh™!ò9î?î0úGàô|êuäé׃È^ÉþáæO }9ñEã8vÿ‰ñÕã-èJçgÔ?Í\à%ûÊÙ* :Ý3\!$Çø|èåïßjÑŠÒEê€B1ó:Ê)\óø^î'îªèÓÒŒÇäÖTð‹6 I:þ‚DõþèƒìiñäÅÒŠÒçß¾÷2.4<4#[Ñ Cýâø.ùíâ*æÌð4^&ôÞ øXù5úÿVÿ–ï·â5åTòÄ8PD+³âé5Ý Öûß9íSê0äPéëöXŒ1¨J¸B(#cáìt×;Ñ.Ò«ÊÊݲ÷‚·;àKÂ>!ŸTõ†ìIæWÐÙ¼°ÃóÛº‚3ÔR L×/ÿ¼ÿÀî.îùð:åÑ‚ÉùÔ6ï!B4²6+;$Q£“ùýïÞÑCÔ­á(ûÔ”-B$¿tH¢ÿÒýìbÜê×á6ÿû&ø8K+ÇÎø@ï¥êùêÛíþéMáàDìžÔ&"<£5F…YóFç¨â¶ÞÕ)Ï%מë«3öA8à †«Ùö†ð©é¤Ò)¿Ý¡Õuú†-¨JÆCž*k;úùú‘ú éÏäÂ×È)â ä5³;8-WžÏÑÙÿ“ôïäÒÙ¥Ô÷ßíÃ#Œá` Ö^ùSïžæ ã;î/ 4Yº Ìý€ø¯þY ¬¿û£î7âùÜfîŸ/L.ß^ýSç]åÒë îžðoñ³ì%è›õÊ20G0º#øpÿ ø íÒÜ.ÔµÕQÙÆàŠú…G5Ÿ3?$?+ P ìÅú©çÑÒÃí¯Ø p1b9„-dwÏ c qø”ëZÛEÊÍÎ,ð7hÖdÎã@ µRûQìÇÛ§á{ÿcМÇýƒøŒÇE Ó9þ±ñ¤äŠï> îÿøÛæzéðò£ôåù#úùŒêï& I%ƒ& È7óÒîìêmß½ßþéëÕçö,('ÙRNSþ÷üIñã]݃Ö1Ñ`âN Š-™3Ö)5¼® ™ýø­ñ°ã:ÎŒÏàì U´!Ê pÓ`g£"`ôä³âÑò ÿg|ιÙ;ø ~ ¡ý-ì8ð¼ÿ»þ[û˜õÃñ.ýõ ä  ¡ ¶üþ9ž ÕŽþ9öÝí&ðëöòöîùdzFß à·û(ö\ôÉíÆã*ã2îÿø±ü% µGäæ h$ÿ­ðSääå‡ãpísý Lºè’üÅ tþº÷-ñÒäËÝûà`êZûåYnVú‚s´ *Ûøóñ4ï¨ç¸æÿñÜû™»Åû1@ D, ÿ©ùøõ&õô]ñÃóÏúÞÿ­ Ç;òž£Å0Hÿéùoòtêè}íŸõãúþ<UŒ §P\Qú|îéä¤àVä;ìvó›D!"š$% „Áˆý9ôZêùÜûÏMÑåÇÓï"='Å%&!‰”ìõù[îTÞJÓÀØõæ£ôYæÐ]í½G OìøÔ–Õäß„íÕÿÈ¢k ¾ ˆÌOyü„êæoé=òüþ ­øHûÿ²ýlL4ÿ‘í)ìóþ’ Ÿ †ý÷ùÔùÎõÞýJ ÃLñèæxñ M o°N8üâûŽõÐöˆõç¦Ù ã¸ôÓ ,%Â.ã"¬zÀßùHÿ^õÎØÉÀÔŒë׳‰"W!P)í.@ ä.þÜÓ-¾à ÕSî4 î7$>#û$r.¡ ìXÌÉÓååý#™r«\Ò4èãê—ô®ÿBMù@ýýC ÚÊíªÞççïû«Î°BþÒþ,ûüˆÕà³Ì©ÔÕéc §+Ó2Í$íX„ Q´ö3Øî¾òÂÅØçö:K&_%<+Ö3e* mº\Ñè­ «ÇÊçsîH胈)Â1r9%ó'Ä„°ç»nÙw÷· Ѓ?iØ¡%ë% ¤èôÒqÏÛâíòü ï:Èû$“# ÇîEÚÍÏœÕðèoû‚‹ `æ '4t"à4çR̲Ä?Öëðð%€-ì æÆ#D#õòýÅݜͻÔÞçT÷[× ó F °]å—îذÓ2ßÚö" z|lÌ H„7m2äâÄ¿¶AÅìÕç#·+ù(%Xà‰+öêrж·Ø·ÍÔÈôµ *'6ª3Í789&Їæçï·Ö!ñ'_ ©Ò0hJW@ !t¦ÖDZw®ÄÊúèª>Gч,¯,?ó ÿî;ÏÊÇ1ÙÚëìùÏ 2b¤ø$z=ððÌÝäÏÒÀè½ c€4‹Š$¹"h ñŒÐ³·¸õÖ«£Ç)D0Ì'Êõ!iÖ ´óÊÜlÃn·‹Ç_æ X56–7WA¹4Âï÷ÎY´í°ÓÇ_æ­ûBi0!õ*›G9I1(åˆàº»© ¸Jשô"('‹')â:¨<1%0¹êpÌû¹I¿×Òç-ˆH#·-AB'Dé(ÝâìÎÑ· ¸¯Ë æDC"¦#—0$=Û.ûéâ‡ÊiÂØÊÐÛ“óò :À$¶/K1uÁù=ëâaÏöË7ÜvîùÓPKù&Ž/ /ÿæxÐѸ'¸¹Ï×î8*,6D4ï2/Ûî%í—ÙiÀ¤²Ö»>×·þÜ%3;ÔAÿJ$KI0Y óî˜Õ¤º³ù½ïÑÓðÂ!"ß0{FÂQZAQ ²ºægÆ´µ¹ÏIí ë!®,:5Üø…ñ(ڱțưÒéwuHh*/›Bý{ì™åÕQÌo×]æãøN‚jg'g0‚#ÜYëØáÂÍ»òÊ'â„þ‰1k1Ñ2/3R"ž5ôÛäѾÀ¹¡Ë[3=ÕD1G»2qùñ½àEÒOǪÃJÏ‘è™2.ˆ?pE7ÑþÐçÁÔ§ÄN¾èÊè–ÛK-]5¤6»+êûëëßpÑkÅBÉÈàCÌA4•Až<>%Vì¥àeÙ;ÑýË[Ðå0—3öGòDF-kxõâÞFÒûÈ•À Æ«à±1Þ2FB9>v.‡Ëú¡ãÊÛÒ›ÂjÀ5ÖXô÷ 3+AW<(ð £óäzÞÍ×aÌ>ÉTÙÒöÉ'o;6<£)n8úzãÈ×Ó7ÊÂÈ<ÞÙƒÕ2A¢>**GÛüBé%Þ¢× ÉàÁ×Ûý^¸;sRMÉ1D,÷ߨÕÉ÷ÁDÔ±ôš®0RS…9£áúã¾ØëÔÜÅ]½Ð2ï¶ v*wEyI)8ë Sêê+áŸÜ=Êî½ÆÌ{褼!º>EB\.Ðú”çáåÞ<Ò‚È+Óvì6,#Î<¼CZ1ÓýßáÔÕTÕFÌÃÅþÔ ö…ý.?DŸH%6•?í‹Ü¤Ô–Å »cÈêV43ªSñZNBR$XÃë·ÜäÚKÍÛ¼†ÅßÏû/!”H T=‹!f}ö¹âBÞÜÓw ÅíÜ,ùÿs<µH 9ô#ÖcùDêåkÚ¹ÊôÈÂÚ£ôM-9¡B˜0¡ 'üúòëñ{æ¦ÒHÌØãïØ¸9C(.æLõ/îDñ(îNßÇÕ¨Û»ï«Q1!B1šŸýµí¾ãåkâÈÕLÒaß ö9Ê6ÃA¡-µððµßÓáÀàÈΈÉWÚ¸ò²>tM¸:Q[ôºâ;ãõàÝÌÅæÔôïl_;~KÕ=J%k‰µòÕí`çÔ¤ÈuÔ±ê" 5¦DÜ2%ó ÃÄô@õÉî}Ø€ÏXÛqî=ß18;¶&Ð cüFõƒì²í,îýÞgÓÜøóÍ'5DB~10{úíá¹Þ,ÝçҳШÞî÷hÇ;gF^5ÔJÏõ<æˆá݀˗ÄÄԛCvQƒ=B Ïùìì ëæ·ÐÃÂDÎf蹊8I;Ó#§ÈŸö óíÑÞöÑçÓÐå€ ï5\Dú1‡S¼÷ëñ òÌê0ܯÓxÖÈè+9ÈDg0Úÿeó¡ì^êõä4ÙÍÎñÏÎâ9 O7ÙK$>z ûr÷2ðÿìÊçÛ ÌXÉfÙ}þL*%@U:P(‹û…ÿžõ–íäæFÚêÏBÕ[ô9_//)‚q È • Þ¨ö ë€ÜØÓoàØþ(2è#¾ˆûëôû<úÿó¼ïVâÂÕ(ßïÁ&Û95B½ÿ¬óhóLíZäjàðÚžÕ‘á“k$41,‡Y  ÔýÏó§è¯ÜûЉÌxØùüH)þ< 4Û r}÷Ué·×¬È?Í îÔP5¬5/))6 m§ÿÕõð!éNÚ>Õ¬ì‘&þ%8C ÆD P þ ñ·åÅÙÏÙAø¨ ^-r"ËýÒñlùgÿûööÛì ÚðÓåìRf6¬6ä#Øñ’ïâíé]ë¶é_ÞÉÜ ô×,*Š›ñÏúiõfêãáÜÓ9ÕQòË:Ý6ñ#| .û÷ùrý¾÷[ñ åëÎèÆÝDû)Ç4~.Ѥ¦|êør÷ÿõ%å|ÕNßÜùgg¦¸© «6q“þqøçÌßÄòôë> Œßùó/ýú Æ ÍØø…éÚó; î½;üåëEíšñ>î—ñüûö&«Rø¡ ŽþÎû3úúéÂÝáJá,àKõ”™*r*#åŠøRyòJëÙÜ ÊÒðð+ A*»'˜¼k}ýûÑû”õ"áðשãÕòôþ= Xð¸•÷® H<øìëJïJýš°ýÙ÷/òFõÆ* Ú ¶ Ú±û³ó1#Œ]¬.ôélèté¶ëSôÐüÔûeý£ –Ï[ïÏü³õnçhÙ÷Ù+à5àÜèE3X#é%Ôµ‚  4øçìâ2ÏCÉ^݆ùÝ}%-¶$ ?o -añ€ÞÝAãíuþ¼ Õ³d à©äþŒþXô€ùFõï éê®õã T=V„ Ô •ÓðÜ ØqáñïL?,¢`°E6ïæêãœä\îñúÈþÞ°‹£F@ûàîSîëñ8÷¬ÿ.øžóû(þ¢ÿ¼  Yÿwð¯êûï…ýò "²3ðùññ ê~ñ·üköaìšì1÷õ^ J÷tßW ˆûõójîòÚ_ÏÚ'ò( ¯$#ϧe4ƒl •ëÃÆ×»Ṵ̂èÌ«$! ÿ$P"©i½Îä(ÔIÔ¦Úåö\d< ßÎ¥ Õóé~ëêòfü¨ üÿòÈù£ªÍÁÞñ>æ ì ùµ–ºèTü}øyò/öÐþ:ø}éÙå}òX” äúŽ™#n‘ûõôßÉÊŠËÃãòk)N&k+;!9r+ñݽ³Ü¼!›'Á!R%?&ó¨"¶%™ RÜ«¾D½çÌ$ç•Áÿ¥ m#è&È)#¦ê ËÛÈ­Øfð ÌSÿ]ÿj…»ä&G:ï1ÔJÓâà.ø3T% šþÿàýÔ(ê ¦ë(Ö$ךè·6¶"pîãâ PÌ4ð6Ë&½SÉÇåí n"_/È/(Í&ü$y!0ãõYÀ« O£³Áãð­f'×,E-04b=@4É vÓi¬Û¤¸ÖØ ø$*à®'y8o<§7 $|òÄõ·%Èâ5õüWÐ&Ä#0*S&ÿyópØÜÓnàÙó +fÕ"—òúæÂÑIÐÐç$ u$ÊwCj ñ£ì›ÎU¾áŽâ£´);1j/Ê/õ0&É è·»uŸi¥>ÉÊô«»!+å(ü6ÕMWK3.õjÌí ˜t²Õ×=õ“µ/j)[A·Dr6ý!ðÁÿ°ïÄÚߌð=3 ù êK-!3„#9 ÏêÒ_ÉÉ×»íû•¦hF>*,1‹"Þâ²ÊÀ4Ð(ìeÿ '§ ,Ý1)†¹ï ØÍÊ2ÏxÞî³þp }0'f'×.zî¾äöáâçµðöÿúDý‘{ mPJ úæâtØÄ× ãõuæ¶ñõuÓ ^ó/ÜVÏ`ÊÙÑ7ãÔ÷bе,ª;žA)6\ìõ¶Òø¿»ÀâÉÓ â5ùØ Që6”Q R;‡RìÕËGÁ.ÄÅÊ^ÙëíAým Ï­8áBð96$é„ÛgÙ0Ö:Øüå?ô믖)b,‰ò öúëêçÉðòî‹ñnø ÿ¤ ®"^)ùûæzÖöÖè­öDþG+óØä'Æ(fªú/è:ÖVÍ·×bäeðºg>.ª>”=á!xý'åCÒ‚ÉšÕøÞá¤é=÷ö À%„GžUp@)†üÞÞüÊîÎ×:Û[æëð)û(d=G8vtÀõæeä°åÅäê‡ðEøÂv$ü¼ýõÃëðø÷M÷…úýÊØbø}ô,ífê’õRþ'úvù¤ü!ý¶¢c"tôõÝêÝåñFþîœ:yú ú»Q¼M ¶ÿÞø#ò°ò_ø?ýyƒ€I|S _ýÅ÷çûùúùOAÝüÂüžýÄ v³ÊþÀñõð÷ð÷6Äjƒæ¸ ô<ÈýbøLúûû¹ÿiæ—!ÿå Š…ýÇîªåñë¯ùã’ Á Úgà·UA¤îKáàßè½öÁÒJ#^ü ° z^úêÉã2éžóŸù±ÿç wŽTðAþ†ímèëôþa)ÿ²Aœg‚Ê·ó-ëOè¤ì)üoa Ñ Ï ®Ì FvøÑç<è›ð¤÷:÷ 3ÿµ|Ü ó(ØiÌÙÑFâåûy ¾_ª°Š(#‹“àØÆgÀ×ÊGÝ[í”û ¡J ÿ.]@ @0*'ÏÛVÃP¾áÆõҰ߬ðºûÔ&V>7I%@ƒ(øJêÙzÑ€Ê'ËÜ¿îèþý€6å=_/~ðöû“ò±ï;ëíÝçÛæ1òù "' 0b!‘©ò®áÿÙ*åŒôÊøùOM4 %_…ýlçÄ×*Ñ~ÖáTëî÷G 0cEËGê(2ü=ÚËqÈ[ÌMÕPß©æ¨ô Ä'[Quf«Q/%$ù¡Ù*ÆPÃÏŽÚÂÝÒâ”öŒ0NCS²:&¤þnî‰ß‰Õ‘Ù)ÜRÝxííhø1Ú1Xfú½úÙûù‚÷ò’åæHþ9}#·#¡ @ëÙ´Ý\ëøÀ)oºùÒø& Ïð1ÙRÒƒÚrã`ó ¬ ~TÖ0Å/ý",ïòÃÕœÒ×Û ßÜå*öúÔõV“5÷ dåÙ/ß5ã”èŒó­ùâôýúÛS(.´'[£úYéç<çaêòW÷5ùþý> Inᦾý(é á3é ò«ù³a*€O nµ B ð¤á±èôføö{U¶%m` >÷ÐîÃäDÜ´æô[÷o8=(X5ƒ ÛùÈޙʺº§ÃãÜïÄ)Ó)c1:~,½ âôgÝCÄè¶[¹QÊ…éî ¡$ê4Œ>Œ@è3‰jú3í'ÞÍÒ@Ë’ÈiÕèÍþn93Ð7ˆ1D¹ò¶èæwá;å¡ñ?ú­U ³}’ ç„ødøùëûé›þà êF%ã+¬Êûýã'ÝÚ”æúÌñ,çEù­— Ê.öObGƒpøWÛ±À:º1Í£×Üzò®m+FÉJ×8àíùç¯ÕÚÑðÆ}ºÞÆiã5@&8FôN‚:}>Ëýùöç÷BðeÙÎÊ3Î|ÛëùÃ"¦8#17„yüfù1ýƒ¬Éùâñ•òïú¶ Å<÷Þï²ñbùHÿ$  B{)ðè Tñ9ÝíÔ›ÜMë ö}ûvm ë¸/42, ýøáœÐ¥ÑíÞ„ñ#€¹ Þ©=â˜ÿNí/åÄååãèè×û €î"¿5ï/õKÜ¿ÈðÃ2Ú‰ó\ÿÞ Báw Å%;8K.Á ð_Ñ€»•¿.Ô•è]„#ï+%!ßó!âõWû»ð¤áÖVÙZãUòæ ¹(e1Ù/W9èžÜö٠ܸä§ðŽüj ÎM!o+(ž·ò2ãïÙÒŸÏÞ-ón X'!<<*Á”÷é¸Þ˜Þ¢ÛOÒ§Ñ”ÞÊïQ ±4EILAj)D óžâgÛ?ÜNØKÏžÖvêÆÿ–Ã7z;¬( *¬øíåì}éËßnßì´ýU¿)ì*`Sþ\ü2ú™û@ùôõ÷ñ÷ÔÎ&$70í?âpæ\ðâ÷ÑúúÙ÷ û ×$×4†3"õ¹×²ÍÝÏHÚ¢æHóƒü´ÿô · Ý1<Ì6†ªðÅÜ<ÔË_ȧÏyàßõ6Ð+Á>sB]5¼j‘í€ãåÝÕÖùÏáÒùá;ð: 5ÚJC.Œ ðWß?Ü>ÚÛõãŒï"ú–€ ò,x&6–yó—ïå’ÓÇÖÞæ¥÷‚Ã5¿<) Lðá:ÜÃå¬ðTêÕâ*ê«ñ&™&‘B@Æ$‘mèÞÒHÎÝÔ6×ÝÚ–í`iV1FEd;´"d îúŸó¦ìžä,ÝKÙíÛ³äöù%'rJF/W”ïˆåÉíÝñêïwñ(ìtäï. Á*|.˜F ºó¬æ•ðÖóÊíôòk÷Xô.ÿâr$~%Ùåÿ¥ãÙjäÃîñrø`ÿ“ù†ùT1"s%Ú{áò™Ý\ØùàÉå«î¥úiþdBV$/ $‡øÖëžé’î‰ôšöŒ÷úÐüP:ûÚá ¹ÿÁñkîöîÑö¢ž P A 鏸1ôWó'óÃøZ÷.òù¦5Ô.*0Ðtø`âOÚ—Ú”åµññó-÷äû‘wþ*4Ó)I4ùÝãÝÍÞŸãôè·î©õmý" •™xÒs š<üƒõ*ñðÚîÂð(÷´n w âºþà=8` : ù¬þn®/ÿ7øðªíºï¶ò«÷¯÷ýl M´3#t(, ñKÞÔçÙàá伿!÷& q %4L1 ˜G÷·åÕÞ]á0ÚÔfÞÀðqô­2A:$œ^õ¸îmî‹újþÂòÝêåêŸîCþ[B!Ã]~øJñéÐïþƒ+X­ÍDë»×BÑ÷ÖÂ奸ÐÌ ˜n¥/òO2R2GpÙ©´c¢[ªãÀ¶àöþJÍ!*,š@ÅVaWU<Êöï+Åi§\žA§Û€ãß#< RkVx?O!5 =÷øÝð̤Á~½Ërßaöøy.D84)J}ô?àsÚMá5ì¢ùú$  r °y²õˆîåà$é;ôiÿE$.1'àœSøàç«ÜñÕpÏÓ¢åù˜(í42K(­~ø÷¬ìŠáà×UÒÿÔyãÔô" Õ"G3i4À)«ý&ëˆç­ççZê±ïƒù?¬ï 8 ¾Iø òÄàÏÙ¶èÆúaÃ'T/»$I lóýíïòL÷1ó­ç¿å"çÌîr8w@k. ûñçÔÞïÝ8ßüßè[øýj'-J%”ôc2 OÿUê.ßÞÖ(Ð1Þ°ûÚT1¼,×›ÿr¶ ewùÜíáúÙéþ‰ ®¡ £ jð = ‘ºöò–ó—÷ÚþŸ‚–Åü«û?ÿ¼ê¢Èþzÿi]td%þ¨ûáúò >÷RøLý&ú¾üT jÁÚüðÙéùñ#ýfÿäÿ°¡ú„ô~þê oÆþüó9ö¼ýÜúÉö/ø¶üÛq —¼þêâ‚è{úàçÿ~øàü ÌçvÿNèŠÚÄÙ›çì÷±G £… Eͪ" gàñç5å+éHñ÷ùÈÿ,ü ¯È!õ,Ê$ ËñÛÚ†Ë[ÌÞܬóÞ*Ò *à .÷‡êÇÞ`ÕÙÓ<ãÚû¹‡%4 3Ç'ÊÇ÷ÄÞƒÙLçÚí‚çÏè?ôüã-/à"'Bó2ÝäÚ@ÝâÕEÜ]ò‹!é,¤(úG ½ù]îæí‘íúáÕÖ;Ú©á“ð½z1;‚.¹Ûòë5éÅç–æã߬ãäúÜ0$´t^Ö¼üúbó¼íæÐåô £>\µÎý~ì T N2ÃþªôžõFÿçü¾û^úoþÀ S î?sO™‹ê-õdêøéLíÊ÷IS 2 óP›6‹L WuÿZýÉüÅõßï§ò·ùÅþWì²È¿õÙè•陸6Ã+ ‰ƒü  ¢ï÷áãà™êÔ÷T210ãáÍÔÐá ÷ÊÌ Ÿô ã)×%í.úsß;Ë·Ïâçö| 7ß Œ‘"—û™ëLä8Ø}Øwé õÏ«ß †/²8©+- @ìÓ;ɋȶÎãÞzôo ×%(V=ÊDp1G¬ü÷å@ÔÕCÓbÍßÙ˜éÏù»$9ÓLXIø3Ô÷òSÕ2ÎïÕ3ÑâÏzãKôã% Å/û.•!´/öü‡ôµëÇà4Ò°Ò¾çñ=!ò94>¦8íoé?óxùMøÜõ¿ëýâóêÁÿ"j!ŸžlGøvõ<ñéòìpùiüDÿ|>• ‰”ø%ôÝùÞÛ¡øõ¾ô†ôÕp\! _þ ï{êð$òø ÕY ɾ  (ù‘øÂùýûø™ñ“ô:ùÝøÍê¼!ddÿ¦ó–î€ñvøÿÒþBú»÷äøñ§¥ÇýÿîõTñAòÈúmÿi»ÿŸýè: iM[E‘ý¥û"ýçüüêì¼åŸç’ò» ŸŠ'ˆ"s—ýý" e<ñ^Ø…Ì!ÌnÞúî ‡S'Q%Ã)¿,˜"{5÷çÓƒ»w½ÂÈ ÛEób™"34p<,1ãsôHÜȲÅÃÏ]âÚùмm«)·.«% Tù£îIç}ßãpì¨ôýÏ¢f¤ äº –ø­éoçcçŸâ.ììüâÿ"%.¡(èIùÕæ`ÛsÜç™éÁäî£øÊî<àIØ9Põ¸×DÊšÌéÖ;ßJäºð5ýÖ 'ä9º7²)TZùßíÓàÊڮ٭ײßmõäH.Ÿ3'‚ õý¦û"üžøÀñËë4æ˜çEô?í E ! ñ ž7z x P3ùÚõWö6û˜ŽIõìáê¥òØþÁcaë  ïËúãî`æ$èíó—÷û0$ ? †ˆ%&öÜAÐØkéû¶Hkî ¢,òüþAîXâòá²éÜí÷öV· Êù!l0\, 7ù®Ü€Î‰ÎvØúéÃúNË"‚/:/>$r”÷ ã¸Ù¬ÑþÍžÖEâ¾ð£ 2'ñ>ÃCÞ2Ù˰î]änäAáNÝšÞ&߸èõq#’/¡,n ÉÒ³üÄ÷žò`ìoå¹ä+é³÷ù"ÑÉºÎøãö€ý¬?Bÿ÷ö‰¬ ) è±ü|ö§ögúèöóšõ‡û: P!¸ÈüëÞá åGïøÜûåü‚øqõþß a ÊC ý/óôî@éèwðzøÓý{˜Jx ý5ñ^õ4„ð‹ Êý'ó¬íåòÁ<ÜÛóçÞèPö4ÿŸ åá– /Åùï#æþãrçaò\ý(ñ§i©$*(»7ûøß¡ÍfÍÕ­àÑõï ø)Ç!P-Ë/y¸*ì”Ý@רìÛ=ä„òÞýç‚e+;C;Ã#“-èçÔÍÇЛۋìÀüŒœ"8,«-%ÜòBñ¾éãƒÙSØžä(ò·£j37)Ëgÿ—îå-åuãá°æòü; t"Ó/³(>¨öçç¬åéæGãÒæzð®?/ë-¸ ³Çþï£èûç„çì!ôöû' +k ¿¡ÿ`ÿ·õ2éNè í7ñzü­³&, ó© øÃî}ïù÷qú÷Ãö›ø·û‘ÿÔÐÙt¤ ­PùçíCåäíèÓô}KôF;ý/þ |7±Gòbè1ç;í@ýÐ &|ü•ûü_§ î 'dÿÄüÒü®û”ö£êoáDåøñùr±þOí{%/ýÓéÀ×}ÊÚχâvõq: n¸ ü#%0@3£~ÿfäKÎøÄ¤ËaÛïDrUz#Î'Ö'lŒ¸ôÅëòáûÚÈßí§ùбI±/êü^öøöùDõAô,ù}þ¡nŽMº÷Çì éð]ù ûHùú¡üÄ„ÙÄ"Fø_ò®ñÿòö%úƒûšüŽ 2 ç½ú{õúú ®ÿ¿ ù›ý< ² (øûïŒí_ñ¦û/jó . ­ç$ ëî(Üï×á?ô#²¾®Õ ï7e çþ¼ê…ÛÁÖwߣì8÷Ä ‡÷!Î#Ô+P&ø ÒñõßÔÎQÌøÛÊéô7e ø½ ¤5q?¾/Iî%ÓbÅlÂÇÝÕ~ðF».C¾AŒ0Ú¡é´àQÞÌÎÅÅϨà“òï =1IC–)ÒÑþcê+ç¹äÖ×£Ô{ÚÐã øÏ (¦*ýƒÂhýÕ÷bì(âRážîÊ ƒ¤c‹ ÍþøÓü0üPùjÿ.ÅùÁú`Ó /þý)þòý·.®û~÷»÷øîú†³ ü UQÿ™üYÿ4R> º_ûïõdò¬ë9êkðâ÷5ˆ ¥À?‹äñ}ê˜ä’Þ=ÝÏá`í 0i*+Õ6G,‡æéôÚþÜŸà}ÚàÛMíRþ^ ˜+íI§EE&ÛÂé(ÓrÒâë,éÁë‚ñ¨øTü*Ä:Å5§ õ<éŸÜfÙ›Ø=ß3çœì9ù±Ú$Ù/ð' ó÷ óÚôæïÕæÐã[äoãÅð´ö$)¯ §üžøÀùùù¸ùcø÷óú]þôýßþrÿ ;œ œØþKþ_«^ó“èåSê÷÷1• ™ " å–ùØ#LjýeÞ·ÓÚÕ„âºõ¡ Çm-^ ÀÔýêâªÚKÝåï†øŒs ÑM¸#»ò ç=áréÞö×ý²O$Ÿ [#ËöUà×ÄÕFßGñsˆšqS!ô!Ýr÷4êéßCáýèê±ð)þÔ ¨Ù%<2ë/5*þ%ã£ÒHÏÖÕŒáí ú "…1a:0b/ø–Þ¥ÒÂÌÉrÑ|àhðѽa*/>VC#4SéÜÛ6×XÏ ÌãÖ)åõG Ð%±5'2‚W lˆú=öØöaìÞuà»éùt !c#þ‚õõ€úØüBtý4û ÷9 ºÿàýßø»ôçôãóoô;ü0 k „Þà æûUñFìñ“÷àö&öäù¥ùþ dÕð ùÜî€ï÷öø›ˆŒþ[ýÿ' Ìå Ñó™ã¬âøî‡û7Š j € æ!P­ ØðoÝ‚×òÚ,êuûõ¶ „F×$I*ñ!Mç[͵ÇHÒyæ®ý\ ·ð±Žþ—ôë~ÝÛ|à4æY÷ø q(ù6À0ç°öýߑԭ׀ÜîÜä›ðŠÿû&;ÈA-Z Ôò°ßrÓeÓàÕÙxãXîüËÛ2õC‚?Å&á\ðtã·Ü·ÙCÛÀß çæï„üä4(.â&ýÈ —÷¿ìâPߎâßëÎü¯ >s ÂtI <ä öìMêÛñpÎw ¥øºè¡çØïPÿýº€£Aö…'ÿ ìïߌÜJÝ®éñøôýÌ@#ê%-Å)+÷jÙ}ÂÂÀ¼Îbá¥ôH¤Ãù$z2[7È&Jë¶ÙÿÏ~ÑZ׉ÝGìèþ`|%@;ç=‰-öÃïµØÔ×ÁÚØ<ÝlèHôÖˆ-.:¥0sNý ë ÜsÚÝXÛHÝÄæó F*†AŒ>¯&)êÚÞÞ=åóî1ï·ê9ç9ë1ö ^)+#ö_ úÏóšðëüðeûÿv" «e @ý0øåùæý{ zþwü¨ÿ™é‘“ô%ë¨è™îÓó÷®ý [ ¾!êŸô$íÌð2ö)øöóHõåû×)Å!„>>ótì¾ì¾óTú@û_üÞýÔÿ7 y¬H"ò·èÏéðpõTúƒüeüÿ\»=‹xü õ…òÂô¹öÍøü7þä ˜¼ âÿ5õdñõ8ýÜÿ ÿÖÿÝz= þï\†õßçdçwí÷¦„tü“ý ̸S•D^ïÝà+ÜèSúŒ ‡ãÔHe >éü¥ðÄæ4äëœø^æb ''_(¬+C&† úç>Ëô¾ðÁ­ÎBá¿òp=e2`CkNûHî.,½ÞBŇ¼2½É¾1ÇØØ.ñmø3Páa-X78¨4ëÒ²ÉpÈŒÃƘÓwä‚¶"6=ñG°:" Íü©òÆîréÆà ÚøÚOæQþ©’$ ܨúÂ÷aöxøÙúäûÝù£ö'ûµŒgDGýT÷TóÝíFî3ù éìý/ 9ûŒðXð©ôÙûDý.ø°ô;ð‘òÊ­)!í „bþ÷ïZìšò\ú|ÿçýðûˆ ¦†þ¨ñMî²ðÍóAøÇþ 1@+~ Eú¹í9è8éî[ðñÐöýù í)){¢ðxèÿéÚïxó†ò¿ïŠí§ôŠ`$V& œ÷ñuô˜ú1üXüoûmøãü2& 㺠tþôèîèð8÷Ç• • Q `åÒâúýì(æýç·ë)ôËÿ‘ " @ ƒù]í8èQéëvíoôMþN:#®'Ÿ$ßî³ÞÇàÉîyöˆö,÷øöaù  "28,êü5ßSÐVÒaÝbë…úçcð 9ï J(Ï"íêü‡ìá!Ö,ÒîÝMëŒøœ Œ€ ô¹þ üøvó§íãé{ìšóÈ1 (<ùÐô®ùÌS~Ô A2ýæ ` ’òÍáØÈÚ•ëµþÝ þµ!¼!!E$û ’ú_æ‹Ö‡Ñæ×ã ðXQŠÜ!//X!f Rõqá‰×ØØßéèõÜ£D.î7/øpýöæpÕ˜ÑnÕØÅáÉðþÄŒ'~8E>84wОêŽÝ‹×;Ö,ÙÜß"èIò˜¬,Y*ˆ ›a³õ¹õöÐóñ|ñTñ¡ó« È0 "æý.÷¨òvôÒùµý.‹ uè Çÿ´õÏóóògôÅöäôbðˆð”ú0^p'o)ø¢*ôõëäí!õyõûñóô^öZŠ% b ¡öŽç§ãšì#ü¨¼ ‰ êƒù Ð'Ï&òSÞ6Ó¦ÖyçÉþ¢¡À!N&ö!B¢?úíñNì¾æ%ÞS׳Ù"ébþlM&{4Ô+¯RìõÌïèë‰ãüÝšá`î2@æ ÇñóþßûEü4ùŠ÷°÷µõ öXüè  oA ãÿîò—èçïìÀð•õµüºÿ^® Ckxß dÿÓõˆïÜê³ç§éµígïÏõ * ÉXչˋøîì÷çuèqìuó¸úr î ‹£)Ñœûžó©íïìõËÿûñ ôÓ Z@þÁý•þ…ÿÀùŒðLðŒô…õÿËÖº¦ ¶ÿù;ô¢ò'ôñèëëçégðÐþ‡#™ ùâù»öoõ`ôdõeóOðfñ÷Áÿ›D»  fÛXo/àIUÚåøÑîHíÞò¥ú[¥ ä<»å†ù £ø”é¶ãTà,âÂêçñøß Ø&Œ1a-hBÿUè³Ý9Û-ÝlâÖë»÷ñýVχ)“1 'öîDà ܵßwææðoú°” 8[$a fõHèàÛøØ(à¿éø} 1{[ì úÙþ1þ³øNïRå‰àåðòe ’úÚçüRú;ý!3iþ¿ùLöyövüK´¯$ý™ùõöf÷Zû+h ]eö äö‚òŸòð>ìWéí·ô×ûë ÈÅ$Vi'{üúÞø5÷éócð×í¨ðÏúk <U´ý+ûOý œeÿÏoòÿ¼  Íü{ógí,íàñIõFøpüãþ.ü áD& Îýÿóóí‹î£ñEõ¸øYû¸þ¦! k / ^æþçüöÿ"ýâüîýW` Ú¼sæÙðµã¼áLêññFöÇþÎjç(þ)v'×Äò]çšâ³Ý*ØØ×~ßKîÁŒ¥% .¸+$!¦DµÍü ðnã:Þ8ßæ}ô5h R  ‘ Ô !¡]B 8õ¹î8ðèúÖá ÿ#ðÍå(æñ'”™¦oÝt¼žáÿ»üšöíQé6êeêTñ£þä f½!}žôBîÔñªø+û!õrîÝïYõçÿuN$?$(Nþ|ì.äè%ô¡üý¶ûÔü³î 3$-"¿ÿÿí"ãtàQãàæoîù–¤°—õ7A èÿKöñîFè@ä5æ"ï8û%Z Å ” K èÜÿÃû¯ó^ìî&ö_þ”9U{3%Öÿºü1õ•îñïýó§úMYs´ýdû-úÝübÌ5!éû#öp÷4ú•ûmý÷öõùÄ Ÿ0`éöïFî$ïðîŠígíåïðõ ‚Ö1!s#¨h îü“ô'îé‡é•êïéuî ÷~ÿ -%€í’ÞûæôâðwðòÙõžújüBýªú ´-ÙþùûôõQöþ‹ƒ  { ´¬ÿýJúôø¤ø©÷+ø¾ö¾ö®þ;Q ´< j?ºú8÷æö\ú ýÝü¥þNÿ”ý zUñ õ+ü÷ õŸøÿÉ M´ ÚßѶýŸýü õ¤í‚ìvðô÷0 pZ ‡=û™ö­ôðVë5éëéñÌüŒµ Î^b ¼ýE÷UõÜöÿõ&öÆ÷î÷Uú*4Ì@ªrýC÷²øÅûoÿ¥!Zþ¼ú5þï -T4 Úüð‚ê€îÙö~ÿÎý×ú¾úÿûIZ“ð¢ÑúÉðýïòó ò…ôøJö¤ô¥ú?¢ z-Âj ¤Iÿøù¹øó îîèòöý ;n~ÜÆƒ ƒÖŽþúçîÔä(äQìæøK®yÇ Ë“@ ñ ®ýp÷îKè°ï7úÓþëÑÇqü ‘ÿÉ1û×ùfø%ò`óžûÖÿ¨ÿŠ[‘ºþöþî'î)ùWõÉö[ú c ɉ û@ù9ú þQ¦†þ,÷˜òcñ@ùÖu(îD\ÿsù»ù%ýõÿíLø¨ðcïyó‹ý–¢  Q¶ß2Tbü:û¡úØù_ûký¥þ•þ—ü¦ûOþ9¹ÿ§9ƒ»²"÷ýýÒúaöÚò òlðVò¯ø×ÿ; zŠñ ~©þ:ùõ{ñOíJé—é`òïýZ ØÉØ ¸ûüvø!øàü[ýõ/ïfð#÷i “Þ o#÷Úð¸ôüþ‰ÿ;4gþ£ uÎ åF¢÷Þð~ïÔî óñúÑß6 ! P 'Ý"1ìûûåû/ùô¤ôüÛ£ cçvûÓôÇñÄòêù²ÿžýký´|þËÿj ó‰B ‰ý‰ïÇäÌå;ðÞöHúyÿ5Øào DÒœüÏñgííï—ô%ütKŽ „ æ z‡øþ¨ýþZþ‹ûHú©þ4]ÑØWÇTöKòÄóŽöçü5ú'~Ÿ — øžý§ïÅå@Þqá€ìZ÷2ò S ­ Ÿ-¾© ÿò‹è(åQèUïlõü«7ï/ äé f,ýNúô'ò2ø­ü½ý³>øöåü©“ å’ë ý¢ü úáú-þbÿpù3ðDê²éíðýþƒ…¶üÃDþOü‘ýeøðªë²ëí»òiÿƒ °‹!èÿÃ÷*ñ0ðñþòø+þÙ…j ÕÞW ïüÎñ²ìað±÷ûÉþ='~CÔÊîo }Ùú|ðÙíÙî²ô+ , ^ ñøþº:¢DÿÖûrøùøÁþ»ðùÉ¿ø›òWóŠö½ú4A~ÙTñF  Ý ÿ…ðèåmçŽñÔýêœ e ùyŒ´ Qã”ý?÷Sïaë$ïø6 UÁ ².ý«ûÕûØþÔUk›²þÛýÅ' ± JŸ4øÞé*å‡ìù6  “ T ¶_8Æ çÿ„ïkáŒÞ’áþèRõ}h 7Ç·’d @>öÈð°înîªî-ð0öüþX! ÖQ…:þ÷ù¥÷Cö)øOøÔõ°öaúÞÿ ‰âØŽl„ÿQüáú`úßú û)ú‚øö÷¤ø’ù»ü€]L QQºl4ÿ#û°ùwûº÷ìYáóßUèÐõÿ“d_SŒ÷µûŸðŸæÄÞïݸçRö̺ ðåæUé  (üJ÷Òñ£íwî ðkóŒúìþ | d m ¶Å¸ÿ”ý€ý;ÿžþ}ûAû¡üˆþ€…ÁzÜþ˜ýuûÊû'#X¨Ðèýrü!ýbÿ}Õ™ÿiÚ™ý<ÿTÛÍÿVýZúYöxõÙøLüÂýÚÿÚÉ> Þ å ¦ 8 «rÿ2öoë`çîé°í°õÀþÝB oò+Ž¥I >“åúTñÈåá æ@ïØû {S 6çqÙñÄÿšøþðqì£îe÷þ* Ü \ )üÏøbý–ãåÈ9ý üðÿ³7,Ó­öið¥ï;ñ¯õµý 5 ‹  F9!ÎN¨þ«ù1ôžïÏîyò²÷ïýä% l ´™DUf ú÷Ë÷v÷žøàúýVý"ýH !¾¢xÿ¶ýMýüŽû4ýÜýbü?ýÑfÅÿú€ûíü1þ·lüIúÅútþÅ' ˆ cnÞý³úeûðüÉýºýUûT÷Óõ ûY H - "ÿ‰ýÚýaþëÿŒÿÃý¬ûÐø°ùFýʸ&w&ÿáþýæüôþÒ›ÖÎkýú"ø0ö÷,û²‚üá÷Á÷üÏ^¶tp `ç÷˜óxôkù‡üücøæóâò õ8#ïç¯ Ý{üÔüñýïü”ûúß÷h÷»ùUþûŃ­ösg·þäý™ý(üÙý.^ÒÿÎþ{þüübü„ÿÛ—ýFü°üþb+ ƒ “i÷úËöUøÚú?ýŒþüLøÃøˆûªÿi 2Q5 ëjüßöäô|÷lùxø¨øÖú=ýÁ=|  á 5 TAAü÷õö³øýïÜ C pý@ÿêý…þ”¡þ8øô—ö ýáh µ€ mŠû–õ)ö=÷¨ø±úùQ÷û È´TAÖü+ûtùÁú>ùpóÿòx÷÷ø#ýc05ë 5 ýgüãûÜúóù÷úáüýüÕû8üÿXª"ºì‰åùý’÷pù‚þÞþ˜-ô'üuúNû?ü|ÿ¬‰òýùù¶ü…VØü÷4ñ=óTû²ƒ “%Þûÿ×ÿÙ,ûgÿMúó€ïÐïòôýl  , Š Y vª(û‹õôôîðÔìØí°ñÚ÷З –¬84púýk÷ôñLëÑèvìyòOú WsNÞ „Œ™q’ÿLõ(ìqéÔì@ôþª8 ¹ Ž  nævÿ?øXóËð¥òõ÷%þÞË(ñ]‚þ ýýÉû¯ú)ù6ùýÍ_è ) ^ýªöÍóSóŸöýÄÿáþ¨þuÿñþ ëP  ýÛñ@íjðš÷¿þ8Mþ¤ý™þÞdЇ ;Ûûhö:ö÷‘ûE˜·‘ý ýÃa7ÝÒÿáúÇù8ü0ÿ䬧P G¼ýÛùÝú–ú ùùƒúøýC'Ú°±  Ãì ¹^üô­ðô÷9úÝýÞüéû­þsê÷­„ E;÷Sô±ö,úbýUþuýiûÌûªþ¶øë}Z»M ÿüëûðü,úÓø˜ýH{žK/þ'ÿœþgÿ¡ÿCÿŠýÀúgûÿ ÎþÁ»Ÿ„Ôþ)ýý·üBücûHúßúûýÌÿ˜ÿkXïRq>Cÿ`þªýVþ‚ÿAþœý×þ³ýaü”þ"‚Ñÿ§³tÃÿÐúÁøgúzü`ýÕþÈÿ1ÜÁ…ÿz•I Ù¦š/úGöªõêôõ#øþqÓW]] K n¹þÎøÂôBóHô ÷ÃúPÿY ç 2Á&þmýyû´ûú×ôÙòõëùmA |Ðmù¢óÊòó ò`ðòføxÿ+© ¡¶ŸhÖîãþ$üñøZòÜíð9õ+ùþÿ 1–dëæý&ýƒýý}ü·üýµüŽýðþ ý†û½ý’>p:—ÿŠûöøtýTC F a #³úò&ïžò•ørý©õdÿ–ë~OØÃöUëœéÜîVöãýÕ¦›XÓÕ ð 3 à Å bù½ï©éÓëÌò2úÃñ ƒké ¿ÊºÿýùúðøŽôLððï$ògø–ç“~"ÔrÄúIø®÷môJó\õ`ôïñQôšú0 õÊ; $xýÿù5ù‹û»üÄùôöçõ´ö2úÑÿ|[H³ à*ÑýEûÌû‰ûqù™ø&ùtùEú˜ýÕ“" M æ ÒŒì9ÿ¨üÉùŸ÷l÷ºøøù©úÒÿŽ ¢}Î2Eÿúý_¬OÛ¯ÐþÄúwù«ûhÿRýûÎþûšùáøïù$ÿq6  > O8ý7ù›ø>÷q÷3ú×ú¡ùëø£ù•þÓo -üØHþqù>õSô@ö<ú-ý%ýõýÃÿoÿt7 K`L ßU÷–îìŽð¼ø·ÿÏb ì ý@*8$±úJôOðŸíDí¬ò´üN“ îø5àî û©ñ>ìþê¹êÝëcïÙôÜü¦ ª |ÕÌŒ~ kCüèõªð,î—ëˆëXò°üc ¬U+ jð‡ÿIþàüúJ÷Û÷:ù ú½ªWû±þ ü”ûþûþpŠ4ÿdÿ'þ±ü‡h dÿjü¬úâû|ýÁýÐþÿúÿVjý$ý¾ÿUT$‰:’þ.þðÜýŸ¬ûNöó”ó ÷¹ün“ž  T —fnân¿±ýŽ÷Pòîêëï¨öÖÿG Ÿì4v "ý2ù<ù¿û§úFöññð¥òcù^á w—Ø 5ÿ+÷¼ñzñ¸ôÊù3²S¸ÿMÿ¬oó $ “Éû õöñEñrôÏú5  ^ „ÍËõ ÿyýëûù#ùìø¤øKú¸ýÆ»Í ; ™ O ¨,ú1öAõ“÷rûýðþ”ãªúa @yÜüRöNô)ôÜö†úÁüÇÿ²< F «ZÒ YiúÏðììÀðÏ÷ÚüoïHë" ¹1J[ þ$÷Èñï~ïròOø/ÿ±),xø;8äIW—ÿRý²ú,úEû¸ü£Ñ >E¬ý^úŽ÷»øâüê²RXQeÿ„¦DBö\vúÔõ©ôÀô“ö!û(Ÿ¹ï…Nçäý®û@úGúÅùwù4úûƒýº/K——n5¼øýæúRùEú»ý’À3±#ÿ˜ÿšØ¡èU0týžúööVô?ö*û«ÿ‹,žÜjxÿŸüø2ô™òô›øNþ­s \  F äü^¤eýAúŒôæï£ð÷õ¤üË ´ ? îþ¼úªú§ú]ø÷¸öôöûùhÿÛ:c " 6 ¥˜þ€öQó™ò\ónõú‹þnÿ Y £ 8 ÆBYuþ±û•÷­õõŒõøÊû-Ð†Æ ¾ g C+¥ÿHþ²üÖúùúƒü=ýYü¡üÒý¹ýþ(ÿ'>Íè°‚ÿû]¦Tv+ÿîû“÷èñFð<òüötý ²Ú%­ q e ð J Ôùï‰çåQêQò´úì3' ’ *é  óÈ)ƒýµûˆøíôóWó[ö‘üžŸ, ^v ŠûWû˜ø÷ ø±ûxþ ÿ¢þuþ¼ÿ=:D + ï –lÿ4÷9óÆò³ôÇø~ü£U‡(“ܱä >ñ[ýV÷ðCí±îÜó úNÂÌ  £  Ñ 1 ª›ëù9õáðî¸íñÆ÷)þ¦ - Ž ,×£fþÎü.þrýhùö4õöjø“ü-/[¢¾‡þYþFÿ_þjþþþHþˆÿ4a€§’Åüùàùü…üŸýcÿÙÿÊþ‰ÿ½® Õ ç Ü`8úõô!ôS÷ø–÷Lú¹þïRD½²55’Uþû¢úûVûÓûþcÊ)L/iþ¿ýJþòý þêþOþsýªþ‘§ç÷‰¢¿³ýf÷”ôtõ0øüÿÑH†îŠ]8‘ïþõùMõwóïôú÷wütA ñŒ6ûŽ©þeþ@ýêù8÷W÷ùEý°I„ ¬ 2 Œ%bþÎüRúQ÷žõ^õõö%ú¾ýO|ç2\YfæÒÿRþåüíúù•÷¢÷¾úŸþî^/çœRÿ£ü…ûyý~ÿ¿ÿ£@ŽÿrþÙþ†”)"ßãMý`ú6øåõö$úªþ„[È/¨‡Xã^)¢9¡ûÂõõ˜øLüÌÿ äÃa ú³»ep>þ$ûNû ûüóý‚ý®üeû%ø¿÷ïû"£GÖ æ } E©¤›gÿÆý ûnö®ó¹ôøžúvþ˜`ñ Æ S ¯çüÄþûµø|÷÷F÷øõùÀýÇáùÆsµí/þûGújùøDúÂýÒßQ~É#mþ¡û úiû¸üüØûûÉúkü‰þê  ’'˜ ùhòµïÇò÷§ùüáþÿIþ ‘`P D?  |Ñÿ¶úõjñòñ^ôÆ÷Qýà;>(‘R ÿ  žñåÿ•ûJö×òüò¨õ—øüµÅ‡c s u  L†ý)úøÙö!÷ñ÷føòùxý>Zê ¤ 9 ò ¹ÿÌùÛööùêüÜþ7蚈…[&çó·üAù‰ùûüý«­ÀZbâÿaý¦ü[üÄû™û›ûÌú«úlý¡<Ý  S¥þtø»õBõ·õdøý³+®–;Yÿõùõ[ó&óˆõQù ý1«‰ ó Ï G“ ·×ýn÷bô·ò8òOó'ö‹ùwüƒFü^s UƒQùúsù@ñ¸ìáíò¡÷¶ýȚЀ{$nÙŠÒþDùXöö«ùªý®Šùð@_ÞÈýcüýûþûsüÀýìþ@ÿçÿ­‘ú^ml"ŽüÜöÕózó×ô]øÎýq9¿) ¸B Káþ§úuôeñkô'ù[ýûZlØÌ_àÝbþšýÐü¢úœøÙøyúåü¬ö·¯ êMŽÿ9ü¸ú#ú4û ýšýlürûÑüiþ­þs$ ‡  ‡/§ú÷÷«ø@ú7üRþÆÿaÿ±’3 ‚ nt}Žüô÷÷oøþù#üƒþjÿšM—^ïN$ÇžŒ ×þßüªûƒûfûêûgýÿÇZEˆY Äe«n1$ÿ¸þ\«=ÿiýÛúMùòù¤úŽü˜,ô–m€Gòß õ-$ôøäóhñ3ðñiõBûÖÿÅeÐ D­Y [àùBôÎïoîÛï&óø€ý€Ú¼è ¾ ® ‰ ( z=†ûW÷¨õ–õõØõ´ùEÿ´®¦ ë&_Ôþ¹ýÜü°üýûû$úðù"ýÎÿ ýÈãà þ]úûù¥ùzùû+ý_þûâ 1Bz<š%þRúø÷Ÿø<ûýªÿ‰qžøÝËÕS:þ=ú7÷|õŸõÐ÷ûCþ®‹2øÄ¦;ñüá.S•ûÿöžó²ðõð õ’úlS t š ÐÒªAi[%ý•õAïÕíïdñ¶öÎþ1½: — ñ !   þ?ú ÷¦õõ‘õÉ÷kü1Š`½û r #±¸ÝýúòùAû®ûˆû¬û)üâü–0T†ÈfüÞúÇûþþœýmþÿþ2ý¼ý¶$ ²6]}þVùuöeøhû÷ý"õ Ô¶ÿüþ4ËaÀ¥ÿdý¶û”ûfüþÔA{ýO’ÿsÿwÿ‹ÿ~ÿKÿ^þÍüáû\ý‰1£7±«FɹÌÏþüúûöwõÂ÷§û™ÿ›¤[oVùŸ7Ó0`tÿ4ûq÷šôzõÑù™þÔô% dŽv9ÿáüÈú+ù+ù)øPøKû!þè¤5»a z̰—¤úö¡óqò€ôù«ü÷ÿè(+Z Y ­é7ñù¤ô|ñèñkõJùý½ÒÀ #I ß + Ç<Ûü—÷×ôeö|ø ú ýûÿ¿^õ•7à3ÔÿGþŒý§üùû!üjü×üþ×ÿ©ŸÿœþíýþýØþ‘͘ bÑû´ÿÒþ>þþ¬ÿwÿØüÓú”ùê÷øþú3ÿ–›{ ƒ “ÚÙ÷XöþËúÕô«ððâò›øóý€Z{ · ù  Û Çü¥ôÉî6ìsíUò™ùéÿ(Òµ ! Ÿ O\ŒÀGþêùöýò§ñ'óËöü}ák ö ä æºÉþuûìù\ùøãöŸöø5ûHÿ7Q Á ö ¼ 3%„ü0û?ú†ûký…ýGüŠù+øbù üë^[¬ Ó »Æþ,ü“ü2þÿÿΗ.ÿíüHû°ú üHþ/ƒöÓÿpØu,ÞbDL/*Sýüûvù¹ø½øËùcûmü>ývþI²1û  Ñ ç l[qüsùb÷HõÐôiõrõöhø0üRÖZ ¥ X )É  öü?ø—öJö8õÔõ{÷ùyû¥ü"ÿ8ï¶ ˆ  ™ ®ÿcûb÷áô5öbù¨üîÿî0;yuášäÏxÿñû=ùùzúÌüžÿ z) ”D´…by}ÿ›ýjûÓû%þ!Ú0v Sÿ"þ®þ ÿŒÿ\ÿTÿ¥=9¬‡·VReÿÿEþ"ûùøEøwû'ÿPR?< ¾7E^ ÍÿZûîö6ó;ñØó ùòþüö 0Ó) šüþ†ýümúSú¾ùáõðòóô¨ùP‡i –#™I›ýþ{ûjù²÷0õzô#ôûòÃôïøâý¥z Æ -®' ïjüzúLølöˆöö»ô õüö9úˆþÌQø ØPk Ä-ñþuü@ûIúŒù.ùUø¸÷ªø~ú`üÿo¾ùíX/|L^ÿÌþìýü2ú|÷yõ¶öúÕþžaÑ¿9¸ß ûþÁþü úe÷—õŽõG÷Úûïô° . > “¿ø$jÿIý úÓöó&ñÚóV÷ÃûL&‘ í7 ½6ùÿeÿ’þVýüEù÷öõwöðù£þVÌ2  p !ïžûþdÿ½ÿ3ÿªýû½ùaùù”û7ÿžýŸª*ÿ¼5EuJ*£þ·ú÷ž÷TûjþÂÿ!qÿÿ{þÃü»ýŒ¶Þ5Á'¡ü ú:ùlû’ýµý ÿ£ÿ þ®ýþÇþu5°ÄûG“þ\üœüFþgÿïÿ‡5À¥ç/Ôà=ó5þãúùWùœûôþQ‹{ " ¾ úgþiý1ýaý8ýmüTú!÷õ¦ôi÷íýÒ¹ ò  /Ó•Ñdÿóû~øšõó óAôCöŒú\d‡p ö ö hšò†ÿÍú¶ö•ôºó-ôþöeú»üYÿ²ÀÄE } ™ ù ú5 ûPø ÷}öúöýøxûnü|ülýŸÿï› w b º±|ýÚú]ú2ûöüÿŒÿdþ©ýñüü ü©üÍÿ> b©VåüÐúæüòÿ‰îNuýüü­úÓùQü&ÿx „µNõÿ³ž”8²ÿ¹ü®ù„øùÄûMÿü|ëõyÛŸÛÏ[©ÿKú:õ%ó@óÌölýÉ^ ² _ Çy÷‘³“¦§ýFú@õAðï*ñþõ-þ r « à RÉÿ‡ýþúýöKôcòÜð)ñàópù¡²¨ ) !³Ê ™¹þÁû*ù“öÝó!òvò¦ô&ù«þ¹fI Ì p D  °ÿúýmýÅû úäù~ùVù‘ùúù@ý³Ê^=,xÎÿ¥þ‡üÃûVümýŒþÿ¢ÿ]^ofô¾)°¶éþVþvþòþÿXÿ³ÿ‹ÿk™ÿ‰ÿî#ku @ÿˆþ6ÿt3L˜Ñÿwÿþ*þþaþ¹þÑÿlì?¯Z øéôä¶ÿhþýümüÂýÿ×ÿ["{/3˜p#®Y!ÿÈýüû±ú[úÇû}þˆbhm¦.Ûÿÿ¹þ ýýû2üÞûWûUüxþþ*µíôøðQ•þõý™þÎþ2ýŒû—ú˜ùÝù üñþ…X  þØû?ûuúsúíû†üýþþ#þÿþ,lÐ " j­GÂþBúŽ÷"÷¦ø®úŠü¹þ/ˆãNÝ˽ú 4„þüü‚ü·ü…üõû+üUý&þ‡þuÿ"b̵§ÖW„iÿÌþËþ¾þÒýúüÿüƒüNûûÂûÕý¦V+‹Å÷¸õä°þþ«ý¼ü ü(ûÉù ùÓùRû°ýôÂ"ÝíbÚ"XXnþ)ûøø®÷Ëö¿örøûÕþ½»¤È‡"ÀšÓþþûúØùÉø7ø¢÷G÷ùæûþ6 4¼ êð îþàüãúúZùWøøšøú±üúÿ]%p –µÖ´úþþÍý?ü‘ûFúøøeùûLÿö{ã ª Å+@xÿÙýÜý·þøþœþüýüˆùøßøZúþý`.™ˆùÁ[íþ®ÿ¡¡ÿ÷þ~þ5ü%úú2û´ü<ÿòÇmšïè€nÒºYuÿ5þæülû"ú…ùKû?þ†—-Þ«{zíö-¦aÿ8ýZûæùløOù¨ü†ÿÊl g,Þþ{ýBüÆûoûrú)úæúýóÿ°¬ðÙø?+£ý@ûNúØø÷˜÷Ýù†ü@ɱ K V ®¤¥H2þý.ý§ûˆùHùRù«øÅøûôþ€CÁ ± m Í@k×ÿýú ÷uõRõùöúù¯üÑþܰ8ÉÑ.‰d\üÒùTø‡÷é÷Ýùóûý)þOÿIí>}—dª”þôú±øGø›ùæúÁû4ý þmýYý5þ§ÿS käö—øÿåûòù£úçûý þ†þ¸ü„ûûüû»þ1‡BÒ¯z¤{±þÖýXþHÿeÿªþzý¦û¿ùIùúdü`j­--«?my¨0 þ6üµû>û4úçùúú4üˆþÜÛyc Öa”¥ÂþÒüvûÝúÏú÷úŽúâù'úŸûþ?T~þ ”Û1QþJý}ýýÓý/þ6ýqûlú­ú=üÍÿÛcÂt«Ì+Lþìü»ü°ý3ÿKÿ¦þsþÙýýü8ýÿyž]?/jÿéþÈþ»ÿª ”ÿ¿ÿÎþ þOþÇþSöGƒ{±ÿÿöþ9ÿ]ÿSÿ¬ÿz(SÓþþký7ý þ¯þÿ^ÿUúq?»ÿ&þÿóÿ¢(V®þýÍû¯û—ü~ýÿ"²:ÆZ*("ÿÈýeüiû_û&ü3þ•(•ÝI°~Ý6Fÿ¾þ¤þ+ÿñþ²ýŸüpû¦úzûàüÿÀªÀ?ÿq2~þ§ü¡ûüú4ûÞûcüþüUýý§þÞÿ2féIN"3‘ÿû†ù/ù‹ùûŒýîþ¡ÿœa ý32’€Õ|õqýúˆøxù‚û@ýÿþ?!ÿfþ”ÿzßi마ç´ý8û/ú3úpûcýºþ_ÿXÿ»þçý²ý@ÿï¿€`\°>Lþ'ü ü ýÙüý1ýßü‹üžü‡ýW5­‘Ýë@¦®þÔýˆý\ý¢üÀû|ûJûû$üþãÿñ Âå!eü ýhûÂú1úú û¥üšýÇýÜýwþÂÿÓÂðM±è_·þ0û[ù³ù‹ûaýUþý"ü®ûFüþM{Ú›Ò‚bôý üüý<þeþ¥ý€üûúúSú§û¥ÿÅÇ¥Ñðƒÿµý/ýýý«üü1üFü{ûUûÇüRÿ zO×øzìýý¤üoüý¬ýñýþ÷ýÞý—þaJÁ¶§Õr$Öý­üý÷þý—ªK–ÿ‘ýŸü0ýÛþ¨ä©*cLÿþcývþŽØ¥2~í\ÿíýïüáü¡ýþ.ÿÐÿ`ÎX¤fÿšÿäMÉqsŠþ*ýÉürýÿw½9ÉÂpîþvþsþ`ÿpíݾÿ¼ý#ü¶ûý½ÿÛN 6]}ÿYü…ûäüûþ1½ÿ*ÿïþþøüDýþÉéï»%:!þÈü¸üÓýÂþªþ þý‹ý þ?þ×þîpî± ûþßþmþÝýÁýþöý°ý þ¸þíþ7ÿ ß bå Ä#£(«ÿ•ýpü ü8ýÄýnþHÿP¸'5ÿÈþ”ÿ¹Æót¡®­þ“üüÁü’ýŠþæÿ‰vÿ³ýèüòü4þò¥¸ÅIâß ýŠüðü/þ6ÿ1ÿßþñýÏûbú½ú³üýÿ8ãN?³)=ÿ±ýþýªþKþÀýSýü—ú(úû=ýïÄO²ô]}³ÿsÉÿLþCýÄü£û»ú&ûü6ÿ8ó§Wî°ï9ÿÁþÙþÿ£þdþÿÿþðýfþ¥þ’ÿú‚žRðÿ‘üxü ýxþˆÿi8Äÿ`ÿÎþ±þ|ÿ‰<NÞÆµ‹ýYûûnüWþ>ÿ*œ׳þýý›ýìý„¼/@ý0¨rþ¼ûåùMú-ü8þ€ÿÿÿ²ÿÐþ2þ'þ=ÿýxÈæî®ÿ‘ýzû\û‘üïüºüVýqþÿçÿHnoCE$¸PÎÿ=ýüû1ûMû“ü±ýhþ»ÿ lêG·@¿^&TSÿuþLüNúú%üßý ÿj°\?)óÚÕïèºÿqþ ýÅûüþ@äG¥ÿ†þ<þoþÔÿ/ù§÷¨§ þªü0üvý*ÿiÿÿ/ÿ£þý:üHüZýLú¼Ë5Ï¥( ÿäü^ûxûAü»üüüuý¹ý/ýÞüUýBþQu5½Ñ_þ½úù—ù4û¸üþmÿÎÿÇþAýküÜüÉþ0ƒ¿&üªÿÿÚýÚü>ýUþüþÖþ¹þ4þ.ýäü‘ýÿåN¼’fÌ;ÿÿ³.ÿRþý5ü«üýÀþ™úUg  ÿµþñþHÿÕÿßÿKÿRÿNÿtþÓý¾ý>þáÿßÀ¨G o3:Sþ<þµþ„þÓþªÿjÿ~þEþiþµþÅÿ/'_(ß—ÿ‰þ‹þsÿëÿgÿùþlþvý5ýWýgý±þ6–*eCÐl«ÿïýjý’þ[é/­ÿéþý|û÷ú¨ûþ¯u$¡£¦äåÿ"ÿKÿÎÿ»ÿ ÿ—þ]þÓýðü¿üŽý ÿ²Þÿù«ä™ôÀ´ÿ4ÿ*ÿ&ÿéþÿvÿUÿ=ÿâþ÷ýÆý´þÒÿņÅË ZIþ$ý_ý"þæþ¿ÿ*ÿXfþXýcýÆþ)FE#ŸeÿâüVûÂûwý(ÿ„ ‰ ©þüýÔý¿þKiDLCêÉþÌüëû¦ü±þzégGÿþqý’ýÊþÁ—|*üòþmýšüŒý&ÿIèOeè`€ÿ5ÿeÿmæ}›ÿîþåýýBþ_ÿøÿZð)H<™lös©Âƒçÿ ÿ%ý„üHý…þkÿôÿª¶Pûÿ·ÿ¦v/"ÖÅãþükú¯ú»ü ÿgW«¥ÿÈýzýÆþŒ¹gN[rÝÿ(þqüCü¢ýÿÿ¿ÿÝÿiÿDþ‰ýØý¶þPöÞ¸‰k,Ãÿêþ™þ“þÔþ]ÿÿìþ˜þþSþþþ¿þ¹ÿ¸òÊðÜcOaÿÈýý\ýþ¦þeÿ Tl¶ÿÿôþUÿAZE²h¢FÕýûû"üòý™ÿćcŒœÿÿ*ÿ¿ÿ ª–CÿÅèÿ~þšüóû³üïýhÿ…|ÿËþBþ þZÿïµ?!ïÍŽÿ3þ3ý:ý>þ[ÿÅÿ”ÿDÿÜþþ}ýáý ÿœ¨çªÄ¾È÷ÿXÿóþÿÎÿuc¾ÿÿIþý^ýƒýþ©ÿ‘«½ ÷Îÿ6ÿÿÿWÿÍÿD×úDÓÿÅÿôþTþ®þ%ÿzÿéÿW'ªÿôÿ¥1Ïÿ•þrþÿÿ7Æñ8F¶ÿÿeÿ+ÿ>ÿQÿ¥ÿNÉPCÿþYþêþ¯ÿ*â±´Fÿpþÿý¦þ…%½vã-!ØþÑýµýEþ9ÿ]:¦?ÿæý.ý}ýÙþ¹¬˜C™°Ô€ 1ÿÒþVÿéÿ÷þ.þÇýyýÃý«þÄÿãûƧßM3:í¦Yÿ+ÿÜþUþþ5þuþÓþ^ÿÑÿ—¨=íuIÄfÿþzýý1þOÿa 9ÿKþ3þÖþ)ÃÉ2A |ÿÓýÍüáü+þ½ÿ¾'ÆÛÿÿ’þUþ©þšÿí_*ZSÑÿ~ÿçþËþEÿ©ÿíÿæÿrÿòþ±þþÈþüþäþKÿy…ýô»jåU«ÿ ÿÛþÿþFÿ¨ÿÔÿ¥ÿcÿ!ÿ¥þPþhþ­þZÿƒœ& ³j;œÿãþ·þûþ6ÿVÿpÿŒÿ`ÿ·þLþ‚þÿÁÿ±¦:jˆžY]Hÿnþþýþ”þÃþ¿þUÿÑÿÿìý\ý£ýÞþÇÇšÊÕê>ëŠþõü˜üýÖývþÿtÿðþýEüïû¬üŠþY*â" ÛR¨ÿþôýéý€þÿàþþýLüü¡üþ$a ƒ$ £Bãÿ¥ÿjÿªÿÏÿ'ÿNþÂý–ýÚý}þOÿêà`(3öÿ÷ÿ½ÿÈÿîÿ¬ÿ>ÿ=ÿ•ÿ’ÿ‹ÿ ~¤ÿ`ÿLÿ†ÿÈÿûÿÇÿÓÿLIrÿ‚þWþ0ÿI¦ýæ¿ÿ¹þ=þJþÿ"ŒdO@öÿ.ÿuþˆþÙþÿÌGš†3½þ¤ýVýÃý›þÉÿFY!Lêÿ“ÿÿæþ¯ÿà¿ñs£Ôÿ¼þÊýýßýŒþâÿj!Ò%ŽF‚hó>äÿåÿ“ÿÎþhþ|þƒþþäþaÿÏÿo c<êõTOÉ'«ÿaÿLÿEÿÿÌþÈþÿKÿiÿ‚ÿœÿÀÿd8ƒC*ÖŒ¨ÿmþÂýÙý]þ¬þÿÑÿ„´„D&GØVN¾„ OgÿhþËýËý4þÿ ŸÚÎ0“ÿWÿAÿÿ¯öˆc6Åþ½ý)ýýÓýZÿîÛ_²•ÿ;þný«ý˜þíÿrk{´Ç`”ÿWÿNÿÿñÿ5[Aøÿ½ÿqÿñþ‹þþëþ¨ÿ %HÐjªcÙo0ÿÿ©ÿOÿVÿkÿûþ“þ¸þÙþÖþÿÿóÿ ‘:ªŽûC©ÿgÿ“ÿòÿçÿúÿ¥ÿÇþ+þ.þ“þAÿ'û¨¢p eÿÎþÈþfÿôÿ'{Á€áÿaÿ-ÿÿ‘ÿ¿‰Iº3 îÿÏÿ¹ÿµÿ¬ÿ´ÿÿÿ…ÿMÿRÿÿ°ÿ¶Æ#Y¨ÿJÿ!ÿÿóþÛþ9ÿ¯ÿðÿÁÿWÿdÿ¤ÿÀÿüÿ?‹ÈýF+¼@Ïÿ¼ÿÅÿ®ÿšÿ>ÿ­þeþ®þQÿÃÿ*¸#üwåÿ®ÿÂÿàÿ KD1rW¡ÿÐþ9þ%þŠþ\ÿQ‚Ÿ_ÿrÓÿdÿRÿÿ€¯žjƒÿéþ_þ9þšþoÿPëBFùšKñÿ›ÿtÿ•ÿ™ïщ0·ÿ:ÿðþìþÍþÿ NêYßÿzÿGÿ<ÿ3ÿHÿ‡ÿéÿOfB<WMðÿ‡ÿdÿ¦ÿ+£çÛ|ãÿ·ÿlÿÿ¦þ`þˆþÿ”ÿîÿCІ|~Ñ4LÈv ¨ÿÿmþúýÎýþ•þ-ÿŽÿâÿpëö¿Ztï²8 šêLÿÄþþ¨ý ýúý þxÿbc¯ÿZÿfÿüÿŸq¼ücÃÿ}ÿ>ÿíþÆþ0ÿ¥ÿ’ÿCÿÿ(ÿHÿ|ÿæÿP¸7—¨Gž#+$ÚÿÒÿ éÿ¯ÿ]ÿÿ ÿœÿþÿ ÿÿ`­©n#&6OPÿÿiÿ#ÿSÿŒÿËÿ8¢ÜËzžÿHÿGÿ‚ÿ¶ÿÑÿŽöþ–×ÿýþ}þŒþÿÃÿJŸÔÉxÆÿˆÿ•ÿòÿZlE7"ùÿÊÿ’ÿvÿtÿƒÿ»ÿöÿèÿóÿÊÿ¶ÿ·ÿÎÿ[µÒ•#¿ÿ…ÿsÿ{ÿ‡ÿÿÉÿP_T3Áÿÿvÿ˜ÿúÿC?(CC"ìÿÿ<ÿOÿÉÿ"9eŒ‚Iñÿ®ÿ¬ÿÍÿèÿëÿÏÿÒÿþÿ!tãõ¿püÿsÿõþ þ‡þÇþMÿ°ÿíÿ(92'&^VEî ÂOÖÿnÿ&ÿÿ)ÿ ÿ ÿVÿpÿWÿ(ÿÿpÿ›({—j-À8¹ÿYÿ2ÿQÿzÿ„ÿœÿÎÿéÿºÿiÿBÿ2ÿ6ÿyÿõÿ†ñ *»kÊÿÿwÿ„ÿ×ÿ*> ýÿäÿÀÿºÿíÿ9s–Cêÿ®ÿ•ÿ£ÿ°ÿšÿ€ÿ¢ÿîÿ,HNXdqkZOEO`MìÿÈÿ§ÿŽÿoÿUÿWÿ<ÿÿñþÿŒÿmàZ’r¬8éÿÀÿÃÿòÿkismet-2013-03-R1b/wav/gpslock.wav0000664000175000017500000025427212124602454016445 0ustar dragorndragornRIFF²XWAVEfmt D¬ˆXdataŽX&=Vuk`TF6#ýÿçÿÌÿ«ÿÿjÿJÿ(ÿÿäþÌþ¬þœþ‹þ€þ€þƒþ”þ§þÈþìþÿNÿŠÿÅÿD‰É@vÃ×éèãÍ´ˆ^%ê¬f$êÿ¤ÿoÿ.ÿÿÓþªþþuþfþ]þWþZþaþhþxþ„þ˜þ¨þ¼þÎþåþøþÿ(ÿEÿcÿˆÿ«ÿàÿD~Ä[«Lžã&Y„š¥—vAó‘‘õQŸÿïþ,þýÆü,ü˜ûûÁú}ú_ú]úˆúÍú?ûÉûzüAý!þÿ üì¼”âæ’|Áæýþþùÿüþýýý@ü’ûéúxúúãùÅùÕùúùCú¡úûœû*üËüdýþ þ8ÿÃÿ=´yÁ?n—ºÕô$6L]ivroZ= Ï{¢€Þÿ)ÿkþ§ýåü#üsûÆú<ú½ùhù.ùù3ùpùÜùhú(ûûûþü þ<ÿ_¡Ôù³:—¾¯mõM{{b%á‡@ÿíý²ü‹û‚ú ùçøYøøÓ÷Ü÷øyøù¹ùŽúwûyü~ýþ™ÿ–ˆl/âjÛ+UkZ5ú¥LÛkõy#º]¸ÿmÿ"ÿåþžþgþ!þçý¥ýbý#ýßüŸübü)üùûÓû»û¯û¿û×ûü\üÄüCýÝý…þNÿõؽ§zIý’]‰„W÷l»ÖÞ»Eÿ·ý}üJû7úAùsøÒ÷d÷$÷"÷N÷´÷Kø ùÿù û:üwýÃþ S“·Æ«ss®º›NÚDÀãô+Pÿ„þÉý#ý›ü(üÖû–ûyûhûxû‘û¾ûøû7üƒüÍüýnýµý þHþšþ×þ"ÿcÿ¬ÿôÿ<ŒæB¨ {æSÀzÆÿ'6'¸WÐ/r±Ãÿ¹þ´ý®ü±ûÆúïù8ù¡ø4øô÷Þ÷øNøÎøùUú[ûuü³ýýþM¡ö.]_Bù|ÍéÍ}ýHpqT$æ£iÿ4þýüûQú¶ù<ùòøÓøÜøùhùßùvú"ûÞû«üxýNþÿßÿ8ÏNÂbг»Æ¶«ŽtR0äŘpC ÖHë¯ÿ(ÿŸþ þtýÜüEü»û4ûÆúdú!úöùìùú>ú¤ú"ûÏû”üzýyþ‰ÿ¡ÇèÝ‘ušRÜ9ijNÄfÿ¶ýjü6ûú,ùgøÍ÷l÷7÷C÷x÷è÷€øGù0ú5ûTü|ý³þàÿ" Ów÷N‰q4ÛiÞG ôK—ûTÐÿGÿÔþkþþÇý‰ýVý0ý ýôüßüÌü¾ü±ü¥ü›ü™üŽü›ü›ü·üÏüýü6ý‚ýÝýKþÈþ]ÿùÿ£XÙ—Nû”Àæá±[Û/dpe? Ôþ˜ý^ü6û&ú0ùgø½÷P÷ ÷÷2÷‘÷+øðøâùýú.üƒý×þ8’æ$DDÀ7{‰fŽã'ï×Áÿ½þ¾ýäüüxûñú’úNú3ú4úTúŒúßú>ûµû/ü²ü9ý¾ýCþ½þ7ÿ¡ÿ^±ÿE‡Ã8w°é(\™Êö4A;#ô°SÞO­ó&XÿpþŒý£üÅûïú3ú‰ùùøcøQøoø¹ø2ùÙùªú û¹üéý1ÿyÏ \“„:É ? ( ×S›¶«{9Þ‚.ÿÔý›ümûhúŠùÑøNø÷÷Ó÷ã÷ø‰øùËùšúûxüzý}þ|ÿkR$〠p¼ìüá·x0ß…,ÏtÄu Û‡Fùÿ´ÿ^ÿÿ´þVþöýŽý(ý¿üXüùûœûQûûåúÎúÐúïú(û†ûúû•üGýþüþñÿïýì¹^æ9dZ°DH1ñ£@äþ€ý,üéúÅùÆøó÷Q÷àö­ö©öìöT÷øÍøÎùëú#üqýÂþa£ÊÓ¾xs«³‘AÐ=ŠÆï-Do ÿæþ2þžýý°ü\üüøûÞûÛûçûöûü:ükü”üÅüôü%ýVý‰ý¼ý÷ý1þwþÀþÿuÿÙÿLÄOÜn™,¯)’Û&%ñ )ŠÍëô߯ÿšþhýCüûú+ù_øÀ÷H÷ ÷üö#÷†÷øàøÕùóú.üŠýïþ[Ì1ƒºÍµoò@ R 3 ÐL„£”r3ð¤jÿ0þýüûYú»ùGùùàøíøùqùäùqúûÄû}ü?ýþý»þmÿ¥8ªm¶ï<Xeuz€ƒ‚‚}rgL3σ/ÅKÁ$‚ÿÎþþMý‹üÊûûtúæùrùùêøÚøýø>ù¹ùMúûüý7þqÿ´J´É°u d ƒ v ¢àøà¢MÝiöþˆý&üåú½ùÈøø÷c÷þöÕöàö%÷™÷@ø ùúû5ücýþÌÿó î¶WÒ-XjSÑhîjÑB£}ór—ÿ5ÿÝþþJþþÎýý^ý&ýñü¼ü‰üWü*üýûÝûÂû¸ûºûÏûöû7üŒüüüƒý"þØþ ÿuXI4#Ò‹$ ð ÑiÍûÃv¶þFýñû úwùhø÷Ûögö&ö#ö^öÏö}÷[øfùœúîûWýÎþ?¶j” x%›Ûè¼c×&N`QC õÿóþúý#ý]ü¿û:ûÙú˜útúoú†ú®úóú=ûžûüküÚüAý²ýþzþÔþ.ÿ…ÿÓÿ#mÃmÅ&„ìN¶q¾5RWE ÃKÁ HWg[ÿIþ-ýü û ú-ùdøÍ÷W÷÷ ÷.÷÷øãøÚùöú;ü˜ý ÿƒÿ|Ù+LK ¨ ü  ÷ š  58Íhü†ÿµýdü/û ú9ùøø÷¢÷~÷‘÷Ì÷<øËøƒùRú;û-ü-ý+þ%ÿ ï¸t •÷M|Ÿ¦‡`3üĆH ÉK È1Û}ªÿ-ÿ©þþˆýíü\üÀû<û²úJúêù­ù†ù†ù§ùíùaúíú±û‡ü‹ýžþÏÿÿE„½äïÜ4 ’ ¾ © a Ú, Å^ÞQÇþ:ýÄûZú#ùø'÷{ööÕõÛõ"ö£öY÷CøUùŽúØûAý¦þ l´îþí±D¯äðÊ~ÓCl¹ç"qÿÌþ7þ»ýLýùü°ü{üYü9ü2ü$ü'ü*ü/ü=üEüXüdü€ü˜üÀüìü'ýmýÇý,þ¥þ2ÿÊÿp(æ¶yJ»XßIŠ®šhúj¤¾©}0Ûÿvþ ý®û]ú*ùø/÷töøõ­õ©õÜõPö÷å÷ ùEú¹û7ýÑþfýûVzy= Ç  ' û • ö),Õ…1Ó‹ÿFþýüûOú°ù9ùïøËø×øþøPù¸ù:úÓútû$üÒü„ý0þÕþqÿÿÿzñY¶OÊþ4`•½ì9Zm{ug:«C»g•ÂÿÏþÕýÛüØûçúÿù-ùxøç÷z÷>÷1÷V÷²÷CøùøùûYüºý2ÿ²<À7ËÔ° S ³ Ý » ] ¾ äÒš)¯q×þ@ýÁû]ú$ùø>÷–ö6ööödöáö—÷pøuùúÄûýBþ…ÿªÐц.¯ ATGÜ„¦+£(ž&¨8Ìc¬ÿVÿýþ¥þKþðý”ý.ýÓüdüü£ûGûõú«úwúPúGúQúúÈú9ûÁûxü>ý1þ1ÿFmžÍúû¼Q ® Þ Ë … þCM(Ùc×5”þôüXûáùøR÷YöõõËôÕôõ£õgöi÷›øõùtûý¨þ>Þ]Ï/ÌO œ j z¿áã×¶“sWVÿ]þý½üüû'ûÞú´úú¦ú½úéú"ûcû¯ûúûNüžüðüBýýäý0þ‰þÝþ=ÿ ÿ{þ€ªM膩%Ü ÈiÒ92 Îÿ&þ½üfûúàøÇ÷Ûöö–õFõ=õlõäõ’ö†÷©øú€ûýÒþŠCúXz W þ \ x H à ) E #ÚmåM¶#ÿ¡ý2üâúÄùÄøøq÷÷óö÷D÷²÷HøùÓù¿ú²û²ü¯ý¨þ˜ÿn;ôˆâ&Ttƒ‡tcK4ùÕ®H º`ósêAŸÿÖþþ8ý\ü„û®úæù1ù‘øøµ÷‚÷z÷¤÷ÿ÷ŒøLù:úSû˜üóýuÿî‡ú<_ A ù ` • w  w ’ q˜ð2_›þÐüûŒùøëöéõ+õ®ôuô„ôÖôgõ9ö;÷oøÅù9û¼üJþÑÿI°ü% õ‘AM0ã{çD†½îJz¾lÿÚþTþâý}ý&ýÜü™üaü.üýûÓû©ûƒû_ûAû$ûû ûû(ûLûŒûßûPüÖü}ý:þÿþÿ÷2GN=ËZ µ Þ Ð †  GQ)ÕTÀ ^þ ü÷ú]ùè÷¡ö‡õ³ôôÍóÄó ô›ôkõ…öÑ÷SùüúÁü˜þpC °2‚› s  b q ? É  6 éŽ%²:Úÿ{þ:ýüûBú•ùùÂø•ø•ø·øûøZùÓùXúòúŒû2üÒüqý þ›þ)ÿ§ÿ‰ú^Â(…îNº‰ëN¦ô3]qiFû”Qx€k9ÿþ®ýYüûÄùŽø÷öÔõFõúôäôõ‡õCö3÷døÇùXû ýÛþ²Žh&É; { { < « Ö ¬ 6 ~ r 8 ¾Z‚žËþøüEû²ùRø ÷1öyõ õÛôòôCõÐõ”öƒ÷›øÍùûküÂýÿQ…›“l«U|~f;ó¨Gå|§7Óf™1ÄOáÿ\ÿ×þ?þ§ýýXü¯ûÿú]ú»ù.ù³øNø øé÷ñ÷#øøùËùµúÇûý\þÓÿRâp÷b¶Ø Ò ‡ 6 ) Ç # 6  Ÿö9HUWþbüvú¶ø÷³õ…ô¨ó óÈòÌò%óÆó²ôÞõ@÷ØøŠúaü8þáž6©äïµ F ‹ Ÿ k  k ¤¸¬’`3ÚËÿÇþÚý ýVüÃûHûíú¨ú€údúeúiú€úúÀúéúûEûvû³ûçû6üzüÝü>ý¸ý?þÝþ‡ÿCñÜÐÀµ™p/ÐH º § \ Ö%ý¦$…Òÿ þEü‚úÙøM÷éõÂôÐó'óÍò¸òóósô•õ÷¥ø€úuü†þ›¯¹¡^ï 4 C ÷ h ~ K à ù å œ y¾êSÿ ýüúDù+øU÷¨öGöööaöËög÷ øúøçùàúéûáüîýÓþÆÿŠRý–‹ð>‡Àõ!ImŒ©¼ÌÏÇ®‚DåxÞ6f{mÿ:þ ýÇûŽú[ù9ø4÷Sö—õõÄôµôçô[õö ÷=ø°ùKûýøþëèáÄ‹# † ¦ A¨ Ú Á \ ºà⾘kþOüHújø½öRõ$ôIó¶òyòòìòœó„ô¸õ÷žø<úúû³ýsÿ­l†s-®þ  ÆdÜ?‹Ê5f¥á1„íÿ[ÿÏþOþÔý]ýêüxüü•û$û´úCúÜùvùùÕø¢ø‚øø øàøLùÛù™úyû‰ü³ýÿeâgðmÜ+ V N  Ë º ] µ ½ † Rb]4þàûÈùÊ÷üõbôóòPñóðïðHñøñóNôìõ»÷¾ùâûþL{˜ŠUÞ ( , Ù B R  “ Ó Å ˜ .²{ÚEÈþ`ýüøúú;ù¢ø6øò÷Û÷å÷øYø·ø(ù¥ù+úµúCûÐû\üäülýðýwþýþ‡ÿ¥@é–K É’K°Cà W e C ïe©±Ž7¸cÿ–ýÈûúùDø¦ö6õ÷ó÷ò>òÔñ»ñûñò{ó²ô@öþ÷ú*ü~þÊ(v£¬ v ý :¥Ó™ å [ š Ÿ…NÞþ·ü³úÖø7÷Ìõ²ôÚóSóó'ó|óôêôôõ#÷wøßùVûÌüAþ¦ÿð'>3²<¤æ! à·x?û²kÂ[öuóT¨å+ÿ4þ&ýüüúâùÕøÑ÷çöövõõ¾ô¹ôìôjõö"÷TøÒùsûQý>ÿPZ|vb  Ÿ Ý Ôp·%M ˜ à ¹p Ž þšû1ù÷ÿôHóØñÇð ð·ïÃï+ðöðò|ó*õ ÷ùDû|ý±ÿÕÝÈwõ.  Ñ / Q )  ) V a HÝ”VîØÿÔþëýýaüÃû:ûÎúiú!úØù«ùuùWù/ùùùúøûøù#ùQù—ùùùuúûÒû®ü³ýÎþX½.Ÿi¯ Í Â } ü 6 # Ä   Ï EpsBúÿ¦ý@ûûøÂöÂôõòqñBðfïöîàî=ï÷ïñ“ò`ô{öÇøIûßý}£2  » úékS²Äz õ . >. åÎÿÇýáû#úžøM÷@öpõæô–ôŽô³ôõ õWö'÷ø ùúû üýöýßþ°ÿn)Ðr –$§2¯6±. `¤ÑÞÈŽ%ÍÔµaêQ¢þÞüûDùŠ÷êõoô,óò_ñëðÎð ñ¥ñ›òéó‰õt÷ ùü…þ¼UÐ! 3 rŒ4xI®¦?w h  ß)tþÌûHùòößôó¤ñ‚ðÔïuï†ïîï°ðÆñó¶ôzöeøbúkümþY4ærÊëØ‡  E X 9 ú “  ~Ö+q¼Oî?˜æ;‹ÿÐþþBýmü•û²úÐùñøøJ÷ŽöïõsõõõôõIõÏõö•÷ÔøNúüÚýßÿóF_b 5 × .=ì@-±Í‡Ú ß  OyœýÁúû÷aõóïð4ïÙíóìrìtìÞìÂí ï¶ð¾òõŒ÷7úúüÅÿyŽÅ ¸ W ŸŠ@ˆ²‘ 9 § û-W~¯ûÿ\þàüˆûcúcù˜øö÷÷1÷÷ýö÷3÷e÷±÷û÷Yø±øùƒùöùpúõúˆû)üáü¥ý‰þ|ÿ£Ô]¬ð- M S + Ö A n P æ - $ Ï /I/ßvÿôüdúé÷‚õIóMñ—ï=îAí²ì“ìèì²íîî‘ðò÷ô¦÷‚úý ¿Ä¦ N §°G}2u<mèÖ a ÇD‚ÿÞüSúøõõ+ô¿òžñâðyðnð°ðGñò1órôÞõa÷ùø’ú*ü·ý-ÿ‰ÇïìÒŒ6µ,€Ì4VuŒˆuRÈbÒ"PP2å~ùþVý§ûåù3ø€öñô}óAò9ñ|ð ðóï7ðÜðßñCóõ÷lùþûÄþ›Šq< à AY^6”tб­ ð òÅ{4þîúÒ÷åôGòùïîŸì§ëëëŠëuìÃízï{ñÍóCöîø™ûSþîrÍêÈ Y Ÿ ‘ -z9± ð  ò Á „4ë a2ÿ*þQýŽüÌû!ûuúÔù7ù™øøw÷ñöwö ö¶õ€õcõuõ«õö¶ö“÷ øîùoû#ýÿ$U‰¯ À § UÄÚ ñå`l 9 } ¦—_ýÍù•ö‡ó¹ð<îìtêEé™è|èãèÙéLëAíïZòeõ¦øü†ÿëBc B Îõ¯ó½ Þ7)´è× ‰  ˆûlÿ´ü–ú²ø ÷¬õ“ôÅó9óóòéòó|óô¸ô|õ^öE÷5ø+ùúûõûâüÃý¦þ‹ÿeR?779KRgi c L  ½ 1 w } @ ¼ é Ë _ ¨­t zþÔûùoöÕóoñ:ï^íÏë¸ê êÝé.êë\ì.îuð$ó,ö}ùýžOèb šƒ¥¦ò;ø.íGA  Ž †ÿüÇø¸õúò“ð™îíÿënëJë¦ëgì‘íïÚðàòõ_÷Áùügþšy •ÇÆ ƒ  e ‘ o 2 Ø w ÷ { íW¼a¢ÑêöÛ¹rÿþ¤ü!ûùö÷döÙôjóòùð ðgï ï ï^ïð6ñÀò™ôÛöaù4ü8ÿ[™Òý ñµ³»I0šX L‘^ á -4þ8údöÀòtïƒìêèÄæõåÌå6æ:çÊèÙê^í>ðlóÒöUúåý^¿êÍ _ ‰O¡íêy¬„e‹ ‰ ~bWTo³þýžûUú3ùDøs÷ÎöEöÙõˆõJõõõòôõôõ$õ`õ¨õöžöV÷'ø5ùbúËûXýÿòQ| ¨ ·  WÅæ¥üäRHÆÇ^ Œ cóO“üÊøõ€ñ)î3ëèæå<äûãEä&å¿æùè´ëðîŒò~ö úæþ"QK ýI%v9_åÎÓº À ZÔ`þÌúÒ÷&õÏòÝðOï.îxí%í:í£ífîjï¯ð ò·ódõ÷Üø’ú@üÕýZÿ»DisnZ7 Õ Ž H ì † r ¾ Þ Ø •  ` Z  ©Ž3®ÿúü&úI÷pô¬ñï³ì§êòèµçêæ¯æýæßçSéUëàíãðXôø7üi½ + ©Îk>bÿÿjGrÒ¢ÿü ¶EÐÿaû÷ówïAìŠélçÞåüä¸ä åúåzçqéáëžî±ñæôBøžûíþÐ? ] ‚.wz+žÝåÖ Ÿ ^  ¸e Áq)æ¡ÿ^þý¾ûjúù«÷>öäô…ó<ò ñõïï]îííÅííítîUï¡ðMò_ôÍö’ù¤üîÿcò‰ iˆLªt$-°™Ç3fQ à5nþ›ùæôfð@ìˆèVå ãˆáà:àxàaáÛâïäõçë†ïâó`øý›^ EÎÕR;‡2>¿¢þšÛñ Õ ´‘¢þâûkù3÷Cõ©óTòSñ—ð#ðèïìïðtðêð…ñ/òôòÂó¨ô•õ›ö¬÷Øøúsûìü„þ3 øC e Yýan!e4ŠZªzʪ %G.îû–÷Kóï7ëªç›äzâØàçß…ß°ß`àÖáçãßæ£êìî¨ó¨øëý&ho +y= R ï !‰ z®Kð Æ= ŒØ9ýÇøôÒð|í©êaè³æ›åå0åÎåîæ|èuê´ì?ïíñ¹ô‘÷Zúý¯ÿYf6Ï - Z P ¿=œÜÜ‘-œæ ú Ý ‚ î½.Šý¢úµ÷©ô®ñÂîÿë{éEçrå4äã@ãˆãRäÌå èÝêIî1òö=û,;W O p"êà 5"õ"(#¶"·! ªcÏ 9ŽáúZõð<ëçævãðàFßGÞØÝÞ¹Þ÷ßüá•ä3èIì·ðSõú¼þD™™ 5[û š ÷hn ]nEý  3 Öu8ÿý=ûˆùî÷nöõ®ókò;ñðï)îWí«ì+ìÚëÎëþëìYí‰îðòqô ÷:ú’ý2ÿõì Ûž%Hg‡ 0!K!ë ôEÙn1n. ŸÚþþø2óší\èÒãXàùÝ!ÜçÚVÚeÚ%Û„Ü€Þ/áØäÑéJïõû("â =&[aˆ ø!Æ" #¯"Î!a K‹à¸QÁ %ŸDý"ù]õìñÿîwì{êøèðçeçEçŒç3è!éYêÅëZíïáðÂòªô™öˆø}únühþXY_mœ ³ ÌÙÏ­[× ìm5ÎÑTIÁ ÈhÂÿàúáõâðìdçmãMàÞ_Ü2Û›Ú ÚLۘ܆Þ-á×äñéšï¼õ,ü»V Ää|¬­"%×&å'B(å'Ò&%µ"îGU ¼oýB÷iñì(çIãkàÞLÝÜÜ÷ÜñÝfßxá.äµç¶ëìï=ô•ø×üæÂR‡ `ÒÛ‚À£3kg ïÿ»aÙ8 g v Oƒàÿ ýúûöÍóžðqídê|çÚäèâRá*àŒß]ߣßgàìáäçþê„ï‘ô úäÿÞý ÐëÅ Ä#0&(2)§)c)^(¡&1$!þ_ÊÊ ˆ7ûöóüìnæ5áqÝdÚØ\ÖŒÕmÕÖW×uÙÜh߬ãUéžïö¯ü&b AŸeÒ—!Ä"l#x##"À ßaP§ãò  0vñþšûˆø¶õ.óíðïî7í¾ë|êréŸèóçƒç6çç>çŽç"èòèê~ëAí_ïÕñ²ôá÷rûGÿa­ œRúô,"ø#Q%&`&ü%%X#!ïì¬ íìÿ¦øqñXê×ãðÞÛÒ×YÕÕÓûÒÅÒ>Ó`ÔCÖ>ÙíÜdá’ç ïÚöãþß±"¶|!1%8(s*¯+B,8,‰+?*ù' %˜!P¦;¤ ˜ýi÷ñWìªçÚã!á;ßÞIÝÝRÝÞ߃à†âÑäÍçüêFîñ÷ôHøƒû¯þ­¡o$ ¹ 8’ÚüÿÜt¯­oâà x kG ÿOùkózí§çƒâŒÞHÛ~Ø>ÖØÔÔïÓaÔyÕ×bÚûÝâé†ð“øßY ´Î= %I)K,X.Š/&0*0‘/c.],[) %C ´~åA«÷cïŽç'ášÜÚØÒÕÔÝÒ]Ò‚ÒKÓ¤Ô¼Ö°Ù+Ý1áyæÎì<ó¯ùõÿô“ »VUo²D E!Í!ý!Â!B!m RÇ ëpÒ 8< 3 Îÿü“øõgñÈí5ê±æãúàèÞ,ÝÄÛºÚÚúÙTÚGÛ¿ÜÙÞ³á·å ëñ²÷Åþ¨ /L´!/&%*Þ,½.ñ/•0 00î.-2*Ù%¾ ð°þnô÷êeâ8ÜñÖÓ}ЭÎ{ÍðÌÍÙÍCÏEÑ9Ô‹ØßÝZäí:öcÿbœ$õ'Þ*®,ß-B.3.‹-I,x*Å'|$Ü d¾°§ ¸ÿ¡ù™ôþïáë=èåãâáÒßüÞhÞ ÞÞCÞ¤ÞFßàCá¶âxäÂæ€é’ìúïÂóß÷Sü  = ’ð;ƒë"&À(×*A,&-ˆ-P-„,+·(`%O!ÿ‡6 Z0ú×ð–çÄßèÙËÔCѽÎÍÌxËÓÊÞÊŸËÍ2ÏñÑÖÜãþì¥÷Q Ûƒ ê&,•/2ü3/5¯5~5—4 3Ý0%.;*¢$[Êa í¹ùãð›èºáßÜíØ¿ÕÅÓsÒÑѹÑÒÓvÔrÖ2ÙMܱßÔãúèXîÂó ù0þÍ; e>Ó”Íq!ë" $#%à%U&&T&Ë%á$‡#¿!};ì¸î ›Ñÿ¬øDñÄéÀâRݔ؇ԛшÏñÍÝÌ_Ì}Ì<͢ΪДÓØßÝBåxï;ú]••©#„*5/µ2ž5Ò7K9û9Ö9î8*7¹4‚1¶-Ñ'a 4X `þ}òçÞ6× Ò»ÎÌÊÁÈ2ÈfÈFÉØÊ͸ÏÓØÞKå©îø6 [øÔð#m'4*ä+-¡-¼-a-›,t+é)·'5%|"ƒÔY¡Ë ëûÿúõ4ðMëæSâØÞáÛÙ“ÖªÔ5ÓÒ”Ñ]Ñ™Ñ8Ò•Ó‚Õ•ØnÜáËçðþøu@ AL &ë+ý/H3þ5&8–9M:B:b9Â7N5%2I.z(· ô6 üòîwâŒÙ`Ò·Í´É^ÆÚÃ&Â_Á|ÁÂgÄǗʽλÓLÛ‚ä4ñþ !g(ù-Ž1z4µ608ï8ø8H8ò65‡2Ÿ/í+¾&Í b¯.ÿ÷gï`è„âEÞèÚØÎÕeÔeÓÁÒÒÒîÒžÓÔÅ՘׸Ù,ÜæÞCâ‰æÆëgñw÷Øý‡ ²ò ÿ$³)Z-ý/?24u5I6–676C5”3M1Q.ø){#XPÐ÷ë¨ß%×ÈÐÌâÇ_ÄœÁ²¿®¾š¾~¿QÁĸÇ)ÌKÑÑØæâ!ñY'ý.>4Æ8 :|43.É$ì| ÷àæËÚÝÑÌûƹÂ_¿ü¼‘».»¼»D½¥¿ÝÂÇÆLËQнÖ|ßëÈ÷8#?#i)ò-è0E35C6é67¥6Ô5—431õ.A,Æ(„$ Ž¾Ï »Ÿþg÷.ðõèQâÝYØ0ÔÑ}Î2ÌBʥȉÇÙÆÃÆ7ÇTÈÊ{Ì…Ï|ÓžÙUáìjùçÁ+!ž*"1¦6£;ù?“CëEòEíEðEðEHD­@ <‹6;0•'(… ”÷šåyØdÏ…Èi½ººººººº)»ô¿¡ÅüË(ÓìÝíþïn2)p0ë5”:b>>A,CD%DCCŠA?ã;*8ë3[/…)½!2ý £÷Îí¹ä?ÞÙÍÔÊѯÏά̼ËËÚÊâÊ;ËÝËÍÌΊÏQÑÄÓ×KÛ à‹æÂî˜÷öË ûª &™,91b5)9~ë8R2±*pÉÿ´ïwá±×ÊÐõËìÇ®ÄE´Àî¿ó¿°ÀÂÄ‘ÆÉÃÌPÐ{Ô1ÚCà&èÐð^ùš¡ P²÷´# (Ó+·.û03æ4w6º7¥8-9D9á8õ76q4Ì1Š.Ò)ê"Ý ÂóÙä/Ú–ÑŽËÙűÀ*¼ººº ººººð»÷À ÇýÍÎÖräÿ÷ Y},5Õ<ÆCïEíEòEíEðEïEîEðEïEEa>Ç6‹.9"Ýû÷ç Ù?Ï ÈÄÁq¼ººººººº»Š¿²ÄlʀОØ$ã;ñ<ÿ• ["b)Z.£1X4c6Ü7¿899w8Š7L6Â431Ú.:,Ö(È$p (@ csý&õììãÝÝÖÑÑüÍ[ÊÇÄ’Á£¿a¾×½¾;¿=Á*ÄýÇ«Ì.ÒþÚ0çÉ÷# ÿ+(g1Í8§?ÇEïEïEïEðEîEðEîEðEïEÆAz:I2Ð''eƒëÓÙ~ÎúÅE¾ºººººººººº/¾xÅfÍêÖP娸þ Ò *Ä1â7=>A_DïEïEïEðEXD A3>5:Â51’+$‡ -üõò‡êDãÞøÙ]ÖÎÓÈÑdÐ/Ï<ÎoÍÖÌjÌ&ÌÌHÌ®ÌlÍkÎØÏ¦ÑUÔ>ØAÝ™ã¹ì!÷__ë¨$è,º28=yA!9O2Ì),}ëóà©ÒÐÉŸÁBºººººººººººô¿VÈvÑ?ßEôŠݯ-t6Z>9EðEíEóEëEòEíEðEðEîE—Aé:¦3+Þ¯ý@í_ßÂÕ«ÏËiǤÄÀ¿Á‘Á ÂeÃ5ʼnÇ:Ê3Í_ÐüӫؼÝã’éð2ö üŽâ *D\·m#:'â*ð-[0ª2Ô4º6Q8z9#:6:£9S8E6_3´/Ž*y"X¼+ùÖèPÛ:ÑÊQÃ'½ººººººººº ¾BÅ€ÍØSéëÿÍ—(•3¤<ÓDñEìEòEîEïEðEíEñEîEïE:BÕ9º08$ñÁúåüÕ¿Ì.Ū¾ººººººººà¼/ÂÈÎÝÕ[àRî¡ü S! ³&À+ò.1b2%3U33`2a1/0Î.M-z+¢)ƒ'Ž%¯#é!, $áþއâ rB?úqòïé{á³ÚIÔŽÏ_ËsÇõÃøÀ³¾/½Ÿ¼½¾ÁµÄeÉ,ÏùÖãõHõ^*³3ë;wCîEñEíEñEîEïEðEîEðEîE.@x7Ý-¥kCïÎÚ봀 ¼ºººººººººº´¾ ÇüÏ~ÜAïdÀ'ë0´7m=ôADEîEðEïEïEC@ð;272Y,Z$;°ï.ûœòCëDåAá²ÞÝÜšÛ˜ÛÍÛ2܇ÜÑÜÖÜ«Ü$ÜeÛQÚÙÄ×{ÖeÕ¾ÔgÔœÔaÕ%×þÙÞÝTã­ëÇõ'¤ ïV%ý-4Ô9 ?²CòEîEïEñEìEòEþDô? 9:2{(ªÎCìŠÙžÍKĵ»ººººººººººL½uƇÐYßÈö•¾$­1%;’CïEïEïEïEïEïEðEîEñE&E²=y5ƒ,³ =øÊå Ù}ÐÚÊHÆä©À¡¿°¿ÎÀÕ¦ÅÉÍIѳևÝ×äŸíõfüŒÙ  4 ˜ _ Ï  ’ b ¾ Ú Ì§sÆ#}' +Ø.h1•3E5D6‰6Ý5H4ª1.é'=ËñTàHÔÌĬ½ºººººººººD¿‹ÇïÐ[ßköŽN%±2÷<ñEíEòEìEòEíEïEñEìEóEìEbC‹9ä.´¯!ìØ3Ìฺººººººº ºº1¿Ç_Ï~ÚºêþN p*Ò0j5ß8 ;7 (Ò\ÜÿYýñú¹øºöõ¼óËòBòò^òôòçóõ‰öøÎùƒû6ýÒþD–±™C·òü×(²-¥$¨<â”`3ÿÿÿÿþÿÿÿüÿþÿþÿþÿÿÿûÿüÿÿÿÿÿÿÿÿÿüÿûÿûÿþÿÿÿýÿûÿüÿûÿþÿÿÿÿÿüÿýÿþÿÿÿþÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿÿÿýÿüÿýÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿÿÿÿÿûÿûÿÿÿÿÿüÿüÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿýÿýÿþÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿýÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿýÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿüÿÿÿÿÿÿÿýÿþÿÿÿýÿÿÿþÿüÿÿÿÿÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿþÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿýÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿýÿýÿÿÿýÿüÿþÿþÿþÿÿÿþÿþÿýÿúÿúÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿÿÿÿÿüÿþÿþÿÿÿþÿþÿþÿÿÿüÿþÿÿÿÿÿýÿþÿÿÿþÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿýÿÿÿüÿûÿþÿüÿýÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿÿÿþÿþÿþÿüÿûÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿüÿýÿýÿýÿþÿÿÿýÿþÿÿÿÿÿþÿþÿÿÿþÿýÿþÿÿÿÿÿýÿþÿûÿûÿûÿýÿþÿþÿûÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿýÿÿÿþÿÿÿþÿüÿýÿþÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿýÿüÿýÿýÿþÿÿÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿýÿÿÿüÿûÿüÿþÿþÿýÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿýÿýÿýÿÿÿýÿÿÿýÿþÿÿÿýÿüÿüÿþÿÿÿÿÿÿÿÿÿþÿÿÿýÿþÿÿÿûÿüÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿþÿüÿýÿÿÿþÿýÿÿÿþÿþÿþÿýÿþÿþÿýÿýÿþÿþÿüÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿýÿüÿüÿüÿÿÿÿÿþÿþÿüÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿýÿþÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿüÿýÿüÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿùÿüÿÿÿÿÿýÿþÿþÿýÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿýÿÿÿþÿüÿýÿþÿþÿýÿþÿþÿýÿüÿÿÿÿÿüÿýÿþÿÿÿþÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿûÿüÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿûÿûÿüÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿüÿùÿùÿüÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿüÿþÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿüÿüÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿþÿþÿÿÿþÿýÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿýÿþÿýÿþÿýÿÿÿþÿüÿþÿþÿýÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿüÿþÿþÿüÿüÿûÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿþÿüÿüÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿüÿùÿûÿþÿþÿÿÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿüÿþÿþÿÿÿÿÿýÿÿÿþÿûÿþÿÿÿýÿüÿýÿÿÿþÿüÿüÿýÿÿÿÿÿþÿüÿýÿÿÿüÿúÿüÿþÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿþÿÿÿþÿýÿüÿþÿÿÿþÿÿÿÿÿþÿþÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿÿÿýÿüÿýÿüÿþÿþÿýÿÿÿÿÿÿÿþÿýÿýÿýÿýÿþÿþÿÿÿÿÿþÿüÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿúÿûÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿüÿýÿþÿþÿÿÿþÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿýÿüÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿþÿþÿüÿüÿþÿÿÿÿÿþÿþÿÿÿÿÿüÿýÿÿÿþÿþÿþÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿÿÿþÿýÿûÿýÿýÿÿÿÿÿþÿþÿýÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿýÿþÿþÿþÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿýÿþÿþÿüÿýÿþÿÿÿþÿüÿýÿþÿþÿþÿÿÿÿÿüÿýÿÿÿþÿþÿýÿýÿýÿýÿýÿÿÿþÿþÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿüÿþÿÿÿýÿüÿþÿþÿþÿþÿþÿýÿÿÿÿÿüÿýÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿûÿüÿüÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿüÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿùÿúÿýÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿýÿýÿþÿýÿþÿüÿüÿüÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿüÿýÿýÿýÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿúÿúÿûÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿüÿÿÿüÿüÿýÿúÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿüÿúÿüÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿûÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿþÿþÿþÿþÿýÿþÿýÿýÿÿÿÿÿÿÿýÿýÿþÿýÿýÿþÿýÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿüÿüÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿüÿýÿýÿüÿþÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿþÿÿÿýÿýÿûÿûÿüÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿûÿýÿþÿÿÿÿÿþÿþÿþÿûÿúÿüÿýÿýÿüÿÿÿÿÿÿÿþÿüÿþÿÿÿþÿþÿþÿþÿþÿÿÿýÿûÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿûÿúÿüÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿþÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿüÿüÿûÿúÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿûÿýÿÿÿÿÿýÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿýÿÿÿþÿÿÿýÿûÿüÿüÿþÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿÿÿÿÿþÿþÿþÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿüÿüÿûÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿýÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿýÿýÿýÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿúÿúÿúÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿüÿýÿýÿþÿÿÿþÿüÿýÿÿÿþÿÿÿþÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿûÿþÿÿÿûÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿýÿÿÿýÿÿÿþÿýÿþÿþÿþÿýÿûÿüÿþÿþÿÿÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿüÿúÿûÿþÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿýÿûÿüÿýÿþÿþÿûÿþÿÿÿÿÿýÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿüÿýÿÿÿÿÿÿÿüÿûÿýÿÿÿþÿüÿýÿþÿýÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿýÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿþÿüÿýÿÿÿþÿþÿýÿþÿÿÿÿÿûÿúÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿýÿþÿýÿÿÿýÿýÿüÿþÿþÿþÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿüÿþÿÿÿýÿÿÿýÿþÿýÿýÿÿÿÿÿûÿýÿÿÿüÿüÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿ             "$$"! "!#"$!%"%#&#'#'#'%&%&%&%$&%$&"%"!$$   ÷ÿëÿïÿùÿ ÷ÿÉÿ¡ÿ–ÿ¶ÿüÿ.G ›ÿòþ2þNýiüuûœúÓù=ùØø¾øìørùOú~ûýÓþØnÖ- e ] Q$w=x Câ  î„þþ`ûØ÷vôcñ²î~ìØêÌéié¤éŒêìîŠðmó”öâùBýuLµ¢  þ \ 5 ’ ƒ  v©Öƒ6TÿÑþËþ>ÿ%†L]£ù D VVûí]Ñ ^ (2¶ú¾ôŠîDè+âtÜ3ØñÔÆÒlÑÑ»ÑÓNÖùÚ´áêcó¥ýdn\(/"5µ9Ï<ƒ>X?3?>ï;98[2.+;!W¬·ø½êGÝ2ÓQË>ÅbÁ¿¾!½–¼½¨¾/ÁîİÊcÒ½ÛªèÿõV8M¥&°-3"7i9m:U:#9Á6è2$.{(ð 5uþ"÷áðýëèªæ*æñæØè¨ë.ï"óF÷IûøþýCÈÞÍ·ÿ›û¹ö>ñlëåèß Ûy×ÕÉÓŽÓ‚Ô¾ÖÍÚáJéáò¨ý; f¥!£+{3:c>xA¨CÇDËDªCZAï=´80%&(¤£õƒänÕ}ÊpÂä¼e¸µã²²—²r´›·ó»^ÁÖÈÜÓ®âgôCË®'ª22;ƒ@„DUGíHFIaHXF.C?–9f1£'W Hþñþä¡Ú¤Ó³Î%ËÉYÈÉèÊéÍ×чÖÇÜ–äjìôûJާ Ž #‡µè 9 òIŒÿöû¾ø<öƒôæóYôöüøý26ø[P$Ä)Ç-ü0E3g4N4Ý2 0ß+µ%~e øsêÒÜkÒÈÉTÿ´»]¹¸ ¸3¹’»!¿ÙÀ˥Õ+ä?õÎo¤(4Ø<ƒB3G·JõLéM}MÄKÀHDM?Z8Í-> ÁýÐì³ÜTÑ<Ès¾ػFºê¹°º”¼r¿6ÃÎȸÐÑÙæÙòBÿê Ãô%¹*-+/}/¨.Å,ú)×%r ;Ô¡ еxþDû"ù7øfø±ùèûæþi?& Ò „|£zï ýõœìÕãRÛ±ÔtÏìÊdzÅÞÄ'ŞƈÉWΔÔnÝÌéc÷ϰ#—.à7#>¼B`FñHSJoJIIßFCCŠ>ê7®-N ìý$ë*Ú!εij¾ò¹R¶õ³é²0³Ò´«·²»µÀOÇCÑ­Ýî¡þ¯t* 3¶9å=s@ïALB˜Aß?A=,9?3%,Š#P, e}øƒïæç±áÝ|ÚaÙ…ÙßÚ^Ý-á­å§êÆïÉôjùmý–Ñýþäöý=úö~ñöì°èóäâ"à‚ß?àwâ-æ_ëõñÚù¹w ©ü Þ)n0e6£:=#?Ú?†?)>;7H0¿'5“ ý-íCÝUÑÇÁ0¼P¸”µ ´Ð³Ü´=·Úº ¿ÚÅ”ÏÙÛíùþÙ?"/9…?NDëGUJsKGKÚI4GsC´>Q8Å.G#ÙtxõFç›Ú÷ÑV˗ƳÃZ¹€ÄoÇÿË›Ñ)ØÛàˆêÿóôü ' ’ªU™ž}}и „ i´«þcüûÝúÄû¾ýŹw ½Lß.Ø#'a)r*j*)M&¨!Þ•øiþ óRç£ÛÐÒ`ËÅŒÁ×¾½M¼¥¼ ¾¼À›Ä˼ӵßEï¤ÿ^õ ò-48?!D=H!KÕL'M0LäI[F³Aè;Ä2'Ð*óâÔüɾwº¸ç¶ù¶H¸·º9¾žÂðÈçÑ—ÜÚê ùëä¢Ï(×.\3‡68R8j75È1}-c(‘!ŠŒÑ ÃƒüT÷LóðïâîËï½ñvôÔ÷~ûIÿÒýw ® , pŒƒ‚ü¦ö-ðWérâØÛ½ÖþÒ"Ð8ÎuÍçÍ¯ÏÆÒ[×}Þ3èNówÿ_ šL&£/Ã7J=.A'DFõFžFEYB‚>æ8"0%8>åò§áwÓ½È{Á>¼ý·÷´#³®²†³²µ¹¨½0ö˶ÖNæ~÷žB(.2:?•BãDF FßD¦Bn?$;Ÿ4i,="W‰<ü½ðeæ}Ý6×DӾЌϑϾÐòÒÖvÚ0à¯æ@íóù¦þá! Ä=HÌþû2÷ óð9î×ììˆíÉï_ó0ø+þÉ d[%}+Y0q479¥99)7w3W.Œ'Kça7õ­æüØóÎ“ÆøÀɼ‘¹t·}¶Í¶Q¸»¿$ÄgÌ×wæÉ÷p ý`*Q5_=ÁBG7JL±LíKôI­FbB=5ˆ*˜ Eûkë’ÜÒüÉJÄàÀ¯¾•½˜½§¾°À›Ã4ÈÏÎ1Ö!àëÊöuS kI!7%a'+(°'&[#D}Rå -ðþ¬ü‡ûsû}ü‰þm . ÚÞ^µ.Åæ™í [úêðç'Ý-ÕþÎ~É¥ÅÃÅÁeÁÂ¦ÃøÆUÌkÓ݇ê)ùuÎ&1C: @}DõG8JMKK”IÕFæBà=Š6ö+“) oúØè¦ØPÍxÄ徉ºY·cµ¿´\µ>·FºZ¾_ÃËûÔ\â×ñ>ÿ`)ù0"7ý:E=@>8>;=;Æ7­2Â,œ%=iáóÿß÷çð0ëëæä°â°âîãNæƒécí¡ñóõ%úâýø?Çíðÿ#ûŒö|ñ)ìØæáávÝZÚ]Ø~×ß׋٬ÜõáÙè&ñ®ú"Eµ€&š.‡5Û:Y>Â@)B’B×A@=c81É'A¹ úêJÚäΩŭ¿øºZ·ß´¬³Ã³.µä·Î»ÏÀ„Ç¿ÑæÞð¥Â#‡/î8ì>8;Ü5Ù.Ã&çeˆúËðRè?áÛÛ°ØæÖxÖI×<Ù+܉à™åëtð¾õ€ú¢þÐ4A9/YÿÂûÂ÷‚óXï{ë6èÃåZä)äNåâçÝë<ñÞ÷žÿ0uó[$+X1m6å9BÑHÒ“ÔvØ–Þçäðéû¹„ ï*ã2š9>EAvC¡D¬D•CZA>91%'´î÷5çÐ×êÌ:Ĺ¾Aºí¶É´ë³e´"¶¹@½[ÂÜÉVÔzâ\óJñ™$„/J8ç=±A]DãE8FiEtC†@ª<æ6Ù.‚%ÖÈ ÿóýç[ÞD×ÀÒ¦ÏçÍnÍ2ÎÐóÒ¬ÖÑÛrâhéPðàöÝü1D ) â p ÿ ¡š\ý¨ù9öbó@ñ$ðð2ñˆó)÷ïû³b¬R &d+‡/Ú2+5T6,6¨4¼1q-‹'”wéù:ì„Þ”ÓçÊ$ÄÅ¿]¼ü¹­¸¸ ¹ç»_¿õÃqË9ÕãŽó”¬ì%l1¢:}@E|H¶J¬KWK¿IéFõBø=ì6È,®†EÿQï/àUÔÓËfÅpÁã¾w½½â½ž¿QÂXÆ_̨ӬÜJèðóÿ 4ä!s&D)‹*•*”)D' $\ kÉf †c.ýüúßùÜùðúùüÛÿ[Kp t*;ƒ¶½f±•) Žùýõ›ìfãªÚìÓ€ÎÞɣƴÄÌÃĉÅ9ÈÍFÓ¯Ûúç‡õßV!-H6=¦ALEäGMIItH)F¹B&>²7Ã-õ *ðþ±íýÜÚÐ)ÇéÀJ¼Ò¸¶{µ¯µ0·Ö¹›½R ɮÒÃÞ5î´ý ý@'˜/;6±:_=°>ü>I>©<¨975_/¶(Á–„ ïùRñÀêžåîá¾ßÿާ߃áqä'ètìñ£õ÷ùÝýùM•Óõ0ÿwû÷Zòhí˜è!äZàrÝÍÛoÛLÜßÞöâ¤èªïøV| ³ Ò)˜0¨6û:Î=…?>@þ?¦>=<8M1#)ów'ÿjï¶ß-Ó]Éq¤½Æ¹·xµ.µ(¶]¸Ñ»WÀmÆØÏÛ'ìLýol,N6?=ÉA>EG¢H‚H(G±D+A¼<ÿ5÷,ª!Tð ÷àéëÝ(Õ ÏyÊ}ÇÆÜźƱÈ*ÌžÐÅÕŒÜåÆí"öÿýò÷ ÆO…c€Û- =N³ÿ‰üú”øø©øfú9ý Á)  ¥"ð&.*,-ó,™+ú(s$’ÿ 8“ôè„Ü\Ó×ËËŽÁø¾ ½O¼¼¾‹ÀHÄlÊõÒ@Þpí~ýÜ 2Î+6e=jBiFMIöJ`K~J^HE—@Ü:ó1Æ&5rõ)åïÖ)Í|ŨÀH½»ï¹º9»‚½ÇÀ0ÅîË<ÔøÞì7ùУP;%B+?/ï1H3T3+2ç/·,Œ( #ÛÇ !üå÷êô&ó•ò!ó½ô+÷LúÚý”H­} ‰ ˜b ô T–èücöOïìçŒàòÙåÔÑ'Î/ÌiËÝ˱ÍÚÐ[Õ Üéå&ñwýo ÇÏ$.¶6¬<–@•C“ErF.FÁD!Bs>ü8Œ0æ%¨(Põ”äÝÕiË`Ã:¾º·UµÝ´£µ«·Þº¿‘ÄûÌ‘×kæªöÑ{ð$ú.7r<¨?ÚAãBÕB¸A–?™<õ7/1£)>w̨üWò éIá5ÛT×$ÕIÔŽÔáÕpØÜá¡æuìAò»÷§üÇü+6+ ú›ý®ùŸõ±ñ!î9ë%éè?è¬éì¡ðö¤ü#k ÷"&b,q1®5ª8D:Í:1:_8ç4Å/N)l‰Z÷äèÏÚÐÙÇÂÔ½˜ºk¸l·Ÿ·¹½»¿‹Ä„Ì®Ömå#ö,'}2;†@²D¾G–I0JˆI£G–Dx@:;$3?)Uï  üÎíõß ÕšÍ™ÇßÃÎÁàÀçÀõÁñÃbÇw̪ÒÚÑãî+ø¨W ð:r G"¡"¡!j-1©æ, ³ÌžþUü ûÒú´ûžýtf Îp¤2Ó N"{"/!aR? Òûëñ«çaÝ*Õ¾ÎÉ9ŪÂLÁÜÀoÁ Ã-ÆMËZÒ‡Û·è÷.“—$Ž/8©>CƒFÑHíIËIhHÒEB>=è5¾+æE Vü˜ë‰Û9ÐÇFÁ½º,¸Œ·¸Û¹±¼‡À¥ÅjÍÑÖáãTò’>&†-3T7“9›:m:79Â6ê2.x(ç LÖÿ$øTò½íqê†èãçŠèDêòìOð+ô6ø;üíÿ}Þ&Q˜þóù´ôï,éxã(ÞÚÿÖ8ÕˆÔêÔƒÖÆÙãÞæÂî¦øgÒu¥%.5š:@>­@-BŸBýA@@r=æ8Ê1å(×– ³ü’ì¹Ü ÑÇ\Á´¼)¹­¶{µ|µÍ¶U¹½ÄÁXÈUÒýÞmï°‹ Â,Þ5}<‡@†C^EF’EüCTAÀ=¡813(ÙÇRõ¿éxߠבÒôμÌÈË'̶ÍSÐÝÓxØÞÔå4ídôû * û žFˆ ð ·Qÿ˜ûDøxõ…ó}ò•ò×óMöíù¢þ<› ~“£Þ%±*/.Ó0p2â22ù/†,w'·¾ ]þŠñ•ä~Ø´ÏÈÕÂI¿¤¼ »‚º)»ï¼ß¿ëÃÊŸÓØßŠïîÿ{Ì ‚-q7>ÒB‚F I^JoJ>IÒFEC­>e8ä.6#O(9óôãÑÖïÍÃÆCÂi¿¦½ÿ¼j½å¾RÁãÄDÊsÑÖÙ!åñ®ü¬Ç©"E'*?,·,,p*“'²#Lqbt áêÏýžú†øŠ÷±÷âøûõýnUU 7 ¬|pR m‰R äbúíñ|éóàOÙyÓÍÎôÊ/ÈãÆ§ÆŒÇçÉëÍHÓ¦ÚwåäñGÿ2 TA(¢1{9µ>€BSEG®G GHEMB;>f8T/$4’ÎòMâ„Ô|Ê ÃG¾„ºî·Š¶h¶y·Â¹!½ˆÁǢГۛêú žÍ$ì-5:1=Ð>j?ú>¡=;P7Ÿ1(+ù"‡™úò¿êÉäCàPÝïÛúÛPÝèßpãÂç{ìuñOöÜúÖþM‹¼Òåoü6ø¨óï’ê“æHãäà£ß¬ß&áä†è^îõºýÆr\+$¡+¬1æ6n:¿<Ë=ì= =ì:I7i1'*w §Ãô¸åè×úÍÑÅrÀl¼d¹ˆ·×¶m·3¹+¼4ÀªÅ8ÎüØRèñø· /Ø(ü2; @ÍClFàGHGïD¹A™=²7/¶$ª@ ú«ì@àoÖîÏÍÊWljÅòÄwÅÇÊOÎkÓ´ÙöáíêÐó>ü÷½ fÅÉoÂÔÔæRI @ý¨ú$ù®øPùûÝý”%I Ñkãä ò$±'h)ã)()'‚#¿vÒ lùEîæâ†ØÍÐ*Ê3ÅðÁÓ¿¬¾Œ¾€¿ŒÁåÄaÊÒÚÛãéù£l'¨1*:Á?ðCGIãIqI¿G×DÑ@Ÿ;y32)œH Õù¤é˜ÚБÇÂr¾Ý»tº,º»½ÿ¿ôÃÊBÒÜéQö$i”V$õ*t/£2r4ð4$4+23/P+?&‡u- v‘üš÷¿óñ©ïsï\ðGòõ\øüòÿ¥¾ ± š { " ¬kðú¯ôî#çgàmÚ×Õ¨ÒUÐ ÏæÎöÏ\ÒþÕÕÛdäyî ù ›½)Â1Ç8=µ@÷B3DYDXCCA >29‡1ô'T 4úê™ÚˆÏŽÆ±À`¼¹ÿ¶¶|¶¸äºÇ¾¤ÃYËGÕãûòüžd!†,Ü4;Ô>GA®BîB&BL@Ž=Z9,3µ+C"P\ Ëþòó$ê¯áîÚÖêÓ Ò~ÒxÓqÕ¨Ø÷ܱâÐè ïõÂú½ÿÐñòÒ @xÿ“û˜÷Ìónðºíéë!ë‹ë;í7ðtôëùP¡v¡É'v,Ö0K4Ã6ã7×7d6†3>/©)!Ús 5ü†îÐà5ÕŒÌzÅÍÀa½ñº“¹c¹Xºƒ¼É¿=ÄmËÛÔ âþñuû#Á.,8N>°BF+H IÛHYGµDü@I<ì4`+¤i&@ñ!ã=×/ϨÈ{Ä ÂÁÀ‹ÀFÁüÂýÅÊŠÐu×Ñàgëáõìÿ2 vˆ#C"š$n%%z#€ £ ð ñPOýáú£ù‹ùzúzüUÿî’ nEh›O¨Šþûâÿôö€íçã¹ÚÈÓ$ÎWÉÆ Ä*ÃNãÄDÇÁËíÑóÙ²åóP÷ž+<4ƒ;?@ÕCvFæG4HBG!EÚA=7Œ-e!\àdð\àÓÊ4ÃÕ¾„»U¹W¸‹¸ë¹j¼ñ¿‹Ä³Ë«Ô¤àñîLý5 Z1$d,d27½9;K;_:[8í4E0â*ö#öÓÜy×øCòÓìÂèæºäºä÷åBèsëAïóÐ÷ üÙÿ sð]µò%tþñùåôïêÝä!à,Ü©Ù0Øå×ÞØ2ÛcßXå¿ìfõÿ€ h_ )0[6Í:Ã=€?X@"@ð>Ÿ<›822Q*À“‰.òÕâ†ÕéË@Äg¿•»ã¸T·û¶Ú·ê¹!½lÁgÇ•ÐØÛŸëçû# ê”)õ2i:?_BŠD‡E_EDÀAw>Ó9Ñ2n*ÎÞ÷ñë!á…ØËÒ¶Îþ˛ʙÊÐË6Î’ÑÁÕbÛ¨âbêò_ùèÅ séø×é k“©ñü‘ùÕöêôÿó2ô‰õø¬ûD¶Ï Iéc%ƒ)q,y.p/H/ñ-]+!' ÞÏ ®åö­ê†Þ¦Ô Í£ÆYÂ|¿’½²¼ê¼D¾­ÀFÄ ÊXÒïܨëHû* <)436;Q@Q9‘0æ%åH÷ýçÚhБÈiÃKÀ3¾9½U½€¾°ÀÌòȮϕ×\âXî=ú£>µÖ!’'P+l-]..Ã,q*×&"ý¢1 `pþlú_÷„õÂô-õ—ööøü­ÿ‹ŒO ¡=ï—MC ¢Oþ!÷|ïƒç²ßÝØ¿Ó¹Ï—Ì€Ê É ÊÞË Ï™ÓûÙfãîÝúÜ7‚"Á,ü4^;€?BšD“ElED¢A>À8‚0O&ÃöÐ÷¹çÜØbÎóÅŠÀ޼«¹ò·o· ¸º½ ÁÆÿÎ4Ùnçö’À!ç+S3 9¦<•>y?X?>>.<©8o3-g%&oîüüò ë[ä'ß™ÛàÙjÙ/ÚÜRß’ãkè¨íöòøÉüÄú-Y_\LcÃý¡ù/õÁðìÛèìåêãã„ã\åèGí7óNúG )t&“,Ý1H6D9ù: ;;i9>671Ö*Ÿ!Mçãù–ë{ݰÒüÉxÃO¿¼ß¹Ï¸ð¸=ºº¼KÀ4Åô̸ÖÓäÜô,T¦$~/I8>BñD²FDG¨FàDB2>Î8¶0'¸_ 1ýïÎâ2ØÑË“ÇqÅuIJÄÆ_ÈlÌhÑD×)ßgè§ñ›úîi Òð´ùšgíå ¹Üÿžü0ú¿øXøùÜú®ý]ËÇ S\á›" %F&V& %g"ÔÀN¢þÏó=é¨ÞÜÕKÏwÉaÅ­Â8Á±À2Á±Â§ÅlÊKÑøÙ™æÀô”²š!)-I6æ<=AžDëFHHÈFVDÌ@5<Û4=+2þ%îÌÞ#ÓAÊÙÃ࿽Q»¹ºI»æ¼›¿.ãÈШÙ0æqó† ©#[*K/â2&56˜5î3,1r-Ó(•"Ôð$ Ò-ýv÷ÂòUïí)ìgìÌí*ðHóýöñúÿÁ*Ùº – Y ù oÐBÿÞùäó“í.çáyÛb׈ԹÒÒ^ÒÿÓàÖ°ÛîâÀëÇõ½Z @û#Â,ö3»9 =@¶A?B¿A@s=9B2Ï)b¤Bÿœï2àÄÓZÊVÃà¾_»þ¸À·¼·è¸B»»¾.ÃÊ{ÓÁß2ïâþfEÞ)g2X9ª=s@B¬B&B¡@>c:°4p-¬$óÛ Óõ‹ëpâÛÖÓgÑáЋÑFÓéÕúÙFß å4ìÂòù²þšq / ½ + ’ Ü'5ý=ùtõ/òïôíiíîßï÷ò<÷›üØÝ ]ž 'î+¢/f2#4¬4ö3è1€.Î)ˆ"ˆB LôJçÇÚ‹ÑÀÉÄYÀª½¼n»ù» ½ZÀIħÊ^ÓåÞîÆý² a¯*G4¶;n@ýCuF»GÎG®FeDAÈ<86 -¥!òáô³æ ÚGÑ`Ê…ÅÂÁxÀûÀlÂÅÉñΉÕLÞþè½ó,þçÇg»y#2&„'Ž'f&+$ƒ íËRß Ÿââý·ú—ø…÷–÷°ø×úÌýx¡ qŒâ¯ZÃÖÑÝ ÍçûVómê}áeÙGÓVÎ@Ê}ÇÆÆÅ›Æ¯È—ÌÞÑÂØãMïŽüZ Q¤%Z/•70=ø@×C¢EQFÍE!DNAp=®7ñ.<$,HHõ‡åy×·ÍÛÅàÀK½×ºz¹Y¹Uº€¼°¿âÃzÊÓÞûë3úp²!Ü*>1J6w9.;¸;;a9n6ü1§,&Tîž ¾›ùUò=ìoçä â{á;â/ä#çäê6ïÍóqøÖüºûbÍ'dвûþ’ú¢õ~ðWë}æ+â©Þ2Ü+ÛVÛÕÜà×äëvòþú`k´î"ï*%1‰6F:»<ê=(>f=x;ÿ7V27+>!“÷çèÍÚ‘ÐÈMÂR¾[»u¹¶¸*¹Äº½]ÁÔÆ7Ï—Ù8èó÷Á?§%Â/8_=á@TC¢DÓDÞCÝAÝ>¢:/4,—!i%Aúîïâ«ÙeÓêÎÇËÊ”Éxʑ̺ÏÍÓÙúßõçðÞ÷7ÿ¿S ÄóÚ‚êD¦L t P/Týèù6÷]õ”ôÛôPöàøzüL/ ^“‹è#¾'~* ,…,ì+*¤&A!¾ßÓü¦ð,åBÚ-Ò]ËÆŠÂWÀ¿à¾¼¿™ÁÄÄìÉ\ѵÚ(èÜö_3$Þ.¶7Ÿ=µAËDÉF•G6G¡EðB)?þ9õ1(!¹ 8ûì¬ÝÓËÅvÁ¿Ò½¥½€¾mÀ5îÇ0οÕìß÷ëø°±¤M!'¾+?.Œ/ž/Ž.w,h)ø$y«ü ¨ÿ-úXöóò±ñzòFô÷öZú+þ;9 ; ÀRÐ#3 »d-üRõîŸæ`ß1ÙˆÔÑ•Î,ÍêÌ÷ÍHÐïÓIÙ[ánë¥ö³;æx'ð/77]<–?ïA>C~C¢B«@¥=î8–1„(Z@ ¶üíÝÝeÒZÉûÂØ¾µ»¯¹Ò¸#¹Ÿº=½ßÀéÅÍ ×Nä&ó ’U´)]1¸7¯;>/?S?}>¶<„9½4‘.H'o›×–ýþóyë,äYÞiÚ1ØNײ×JÙäÛùßëäSêðõòúµÿ°Ê×Ê UPÿû·öVòKîÉêèhæäåæ»è$ìéðÙöÙý§Àk'½,L1ú4š7»8Ë8¹7ö4Î0L+—#~; ,ÿñä·×ÜÎ[ÇVÂì¾y¼»Åº »–½°ÀÅ Ì Õá¾ð`k½+ã4»;@)C7EFÑEhDîAq>9ÿ1)mU>ò¬åKÚ‡ÒŸÌ$È®ÅhÄUÄeÅÇËæÏ…ÕæÜHæÒï'ùóü þÈ63Åß¼`gš ÒOaþûÃøf÷#÷ô÷áùÇüƒøÝ ûµÓ X"W#ÿ""!Éç°- ®hù™ïžåÛÛxԙΘÉ(ÆÄÃÃ=Ä»ÆÛÊÔÐcØãªð›þå :4(1<9Z>ñA‡DFSFzEzCe@M<µ5¿, !ÞG»ò¥ã“Ö˜ÍLƨÁˆ¾}¼—»Ó»-½‘¿åÂçÇJÏá×Àãéð þ¬ ŽA!g)¼.¹2c5¥6’645¦2/§*Ï$óà ð´ýL÷îñ¸íÔê5éèèÎéËë´îLòbö§úêþÔEüÌ ’ 8 ¹ uëþ¯ùåóßíÔçâÞÜ(ÙzÖ(ÕãÔ¾Õ ØËÛÍáSé/òü½Ú7'¸.5ö9/=?ÿ?æ?Ç>—<²8˜2ù*: ‹õ1æŽØ×Îׯ—Áæ½9»¤¹B¹þ¹ø»ú¾ÃMÉ/Ò1Ýì:û` j&«/.78<9?-A BÚA›@b>û:º5«.O&÷áí÷êìjãpÛ֯ҔйÏÐŽÑ Ô›×vÜõâÐéÒð˜÷ìý6á d³ÓÍÊ ä Z_9þ úRöó£ð%ï¼î†ïñ³ôùTþs? `šŽ |&ç*.J0|1q1/0—-À)²#àßÍùí^áªÖéÎȀÔÀœ¾½·½Þ¾!Á›ÄJÊ8Ò>Üiêbù›Îú% 0w8ï=³AiDFwF½EßCó@ÿ<7q. $¤Ú.ø êÝÜmÓQÌÚÆhÙÁÏÀ Á;ƒÄ$È·Í3ÔQÜçüñ½üÚ,T"U$l'1)›)Ç(Â&È#4ï4T‘.sþzúy÷õ½ôõ‚öìø)üF´ y¥2ür¡ ¦³ùÏð[è àÉØbÓÏÀË~ÉtÈ»ÈeÊpÍÓѾלàÌëøì2X{*¡2q9ñ= AC.DDæB•@?=8 0f&d òùšêëÛtÑèÈÃR¿˜¼öºzº&»ð¼Â¿’ÆÉËѹÛ^éi÷J°9)ì/P5í8ó:º;g;è9c7&3ü-Å'`É+ ×(úZò¡ë9æ3â¬ß™ÞóÞšà\ãçtëHðRõ>ú×þ×h¢ Ò ÓØÒ œû»ö«ñªì èäæàÖÞ ÞŸÞ«à/ä(éwïóöpÿ‹-Ó%ò+m16;9;ç;†;ø97E2,Ã#Ĭ éüÕîëà<ժ̸Å3Á¾Ñ»¼ºÃºó»C¾Á‹Æ(·×ôä ôm¯Q!‚,ð4=;'?ÕAhCìCGC›Aå>;57-¥#º˜ ¦üHðÒäåÚÔMÏ×˶ÉýÈ”ÉsËgÎbÒ@×êÝæjîªöxþ“Ñ ïÛjª”Rù¿ß ‡ «­ü1ù~ö¸ôônôÿõ´øfüù?ü ìÉN9"Ü%P(µ)Ï)¤(&Î!”ä .¶öØëþà~׊ЕÊ(Æ:éÁ ÁgÁÊÂÅʯÐâØÖäòÖsòX*C3s:?WBžD³E·EˆDEBó><:é2Ø)ôÿðÕáëÕ¼Í ÇÐÂ8À¹¾@¾æ¾ÀÃ.ÇKÍœÔÞê-ö÷3 zˆ c'å+Ì.k0Î0ú/ .&+'n!¤ˆk šOÿÒù:õÈñïvî¢îìï<ò_õ#ùKýŽº” È D­2(ä Œ1 ûdôdíWæ•ßßÙšÕ´ÒÆÐêÏ6нÑ|ÔâØ–ßpèò›ýE 7!È*2Y8<+?Æ@nAú@|?÷<´8%2*W3`uòªã¹Ö›Í(ÆTÁñ½»lºdºŒ»È½Á¸ÅÜÌ«ÕåáDðÞþ2 ïó&=/Ý5m:>=¥> ?n>Þ<ò95‡/Œ( -D ¾þÆôÖëä¼ÝzÙÚÖµÕÃÕýÖnÙõÜ÷áœç¢í¹óŸùÿ¿¡u 8 Î D © ²«PüÉ÷]ó\ïì~éèÇçÈèë²î…ó‚ùX L^ H'o,k0y3g56|5„3,0+ó$P.l÷zê¿ÝÝÓÌòÅÝÁ(¿j½¹¼(½ª¾IÁ<ÅŠËÜÓøÞWíPüf E¬'1É8Ñ=(AxC­DÁD´CAg>Í9Ä2>*c°%õ:è_ÜÔæÍ É4Æ£ÄLÄÅûÆ:ÊâÎlÔrÛÏä†î.øYÔ \«ª6 ="Î"õ!Ö †Æ©l Tµÿ£ûqø.ö õþô"öFørû[ÿáÊÙ ÅK52# Ä  Çû›ÂþÃõeìãQÚÇÓœÎQÊ_ÇËÅQÅûÅÓÇqË”Ð×Ûàãìàù] "¹,à4;?ðA¾CrD D‚Bã?8!;F6„/›'³£åøñíä®ÛóÕPÒëÏÐÎïÎ>МÒäÕ¬Úûàèzï¸öšýÊ0 … ¹²fëL¬B 5Ó]þ ú$öäòvðïÍîÄïìñGõºùÿ5Û Âž) ¯%Ù)‰,B.ë.b.«,·)¾$noV UÿÊóè—ÜúÓÍbÇ„ÃEÁñ¿œ¿RÀÂ%Å$ÊDÑ0Úÿæ!õÀvÎ , 4);O?9BDÜD…DCy@èߨØÉÓÐ`ÍÀË]Ë?ÌyÎþÑäÖ\ÞUèvóyÿì ˜¾$µ- 5¦:;>˜@éA?BqA ?Á<8ß0+(‡. TþvïõàÕu̱ÅWÁr¾¼Ô»1¼ª½.À§Ã6É ÑnÚmç4õîBËe'¢.>4X8‘:¢;w;1:Ö7Ì3´.­(n Àï XLúòàêøäuàtÝþÛÜXÝà¹ãGèeíÕòGø„ý6Ci Œ Ž j  ¾iLŸü™÷wòŒíéLåtâ»àBà1á€ãMçoìßòaú¯£ Ö N&€,a1R58L9s9z86ø1 ,[%ÚÑô´ôVç²ÚwÑËÉ6ĨÀ0¾Ã¼j¼B½ ¿ ŸƧÍ0Öâßð¶ÿ€ëO)á1ë8u=W@)BçBˆBA¦>;[5Ñ-²$98 ^þáñIæçÛÅÔ³Ï÷˓ɓÈôÈœÊ|Í\Ñ$Ö¢Ü å±íTöŽþ&Ü ‡ò ¾ûÅÎ8 [qÈþ•ú ÷gôÀòAòåò»ô§÷”ûM°x a#v!‘$¥&Œ'@'š%q"_Ú3’ü_òèÒÝ¥ÕÏQÊÆ5ÄÃÃþÃ^ÆTÊ(Ðj×âàîküP 5X%Ù.¼6X<Ø?YBÖC.DjC‰A•>9:g3Ï*õ™ó_óT娨-ÐÉFÄfÁ§¿ü¾Z¿ÃÀ ÃÇåÌÔÝüèõö\ Ý9 i'*,T/.1Ä11O/x,”(-#"¥ µ×þ¶ø~óoï’ìë¸ê¡ë°í©ðrôÁøaý|~ Ê 0…©—GÐ CЭú ô)ícæößÚ‘ÖÔ‚ÒÒÛÒÓÔZØÉ݈å‘î¯ø€Ô1%-¡3ä8j<_>e?g?f>[<“8­2D+õ {÷¶è#ÛbÑ`É´Ã-À¥½-¼Ô»“¼t¾ZÁŸÅIÌ´Ôà*î~ü¯ TÓ$‰-I4Q9z<>¡>5>Î<:Ü50B)æñä ÿéô—ëxã¼ÜYØ‘ÕMÔ4Ô1Õd×Óڸߜåìò ùÿ„$ ³ 2luT ì û„Ïüøyóbï ìŸéRè>èyéìèïýôû u\![' ,„/2`3ƒ3T2Ñ/,t&.ÎêüžðYäÙôÐÊ ÅÊÁÿ±¾º¾Í¿ôÁxÅËÀÒ|Ü,ê‹ø?ÏÎ#Ò-Þ5¶;R?ÑA=CŽCËBï@>Í953+ …¶ ÷êÞÕÁνɒÆÛÄWÄúÄÀÆËÉdÎßÓÜÚ)ä îøl a#"´$k%Ý$#΃ô5 } ZûX÷IôVòŽñôñ‹ó(öÁùþéM NÑ”e]EÀÄoÚ ?ÞûúòßéñàÙLÓµÎ˗ȇǢÇòÈäË6ÐËÕÞ.éZõ$T^(i0’7müèüªý‹þdÿ;°;•ÆÂ5³iºÿ ÿpþéýŒýYýPý€ýÖý\þÿÊÿ–sG ®0y–u “ÛôúðÿÝþÑýÞüüaûîú¯úµúîúcûüÙüÁýÈþÇÿÁ¯z*žëýÝ‘}Í S¦ÿÿ„þ'þóýîý þ`þÎþ[ÿýÿ™EÚ^¿ø ã—v°áÿþþþBý…üäûyû7û/ûbûÇûbü,ýþÿ43!ë†ò% áwÕ>Qk‹ÿÄþ þ†ýýñüçüýaýÔýaþúþžÿ+¼+ƒ¯¸—LçZÏÿ%ÿƒþæý_ý÷ü°ü›üªüöücýþÄþžÿ…ud<ÿÿ/-òß('ÿ"þBý‚üòûŠûdû`û¡ûüü>ýùýÉþÿDîxã:#ñ“&¡šÿÿ¶þmþAþ=þaþ¦þÿ™ÿ0ÛŠ1ËD¤ÏÕ¦G½4HVÿ]þjý‘üÐûAû×ú«ú­úíúXûúûºüžý‘þÿyf.ãb»äÛ©MÐ>™óPÄÿHÿãþ¨þ†þ“þºþÿfÿÒÿF¿-ÎöóÑ‚†åÿ/ÿoþ°ýýiüðû£ûyûûÅû<üÑü—ýwþlÿdaW1ï‚æÙ}ã7c‹¦×ÿÿVþÁýUýýöüý8ýýúýyþÿ€ÿ_¹ëûÎŒ,ÅÿQÿÕþdþ þ¹ý—ýŒý²ýõýgþõþ¥ÿ[*ûÃ|àýë¦1’Êéñüÿÿþ:ý€üòûŒû\ûXû†ûßû^üúü¯ýlþ.ÿçÿ‰àц+¿\üÿ­ÿmÿGÿ@ÿRÿŒÿÕÿ;¬6³9¡ý3I9ü›h¥Ôÿöþþ@ýüÜû^ûûêúû=û±ûJü ýâýÎþ¿ÿ¥ƒQ÷€Ù äš*¨s×BÊÿ[ÿ ÿÔþÅþËþòþ+ÿuÿÍÿl¬áööЖ4ÏÿCÿ±þþýýŠü;üüúûübüÙüoý/þÿçÿ˵–\ŠßÃdÒ$`…®Úÿÿ[þÁýMýôüÏüÃüãü ýuýßýSþÊþ?ÿ¦ÿûÿ4ZgY3ÿÿ¹ÿhÿÿÊþ†þ[þEþKþuþ¶þÿ˜ÿ'Èy"Ê[×0coFÿ}äK[|ÿ‰þ²ýäüAü¹ûcû6û8ûfû½û:üÐü€ý<þúþ¸ÿ\÷xÞDE*ü±i ¾o4 ýÿLâ>šï;q‘p1ÌL¯Gÿ‚þ¾ýýfüÞû~û?û4ûPûœûü­üký<þ ÿã¾}&¨9@%àuØCª ·ÿQÿÿãþÓþÞþúþ(ÿdÿŸÿÞÿ-FD1Æÿtÿ ÿ¡þ,þÂýcýýßüÅüÑüýPýÊýYþÿÏÿšm@¯=¨ëÿí¥>«ÿ:d޼ÿùþ;þ¥ý#ýÉü–ü€ü—üÁüýmý×ýMþ»þ*ÿ„ÿ×ÿ(3*ñÿÇÿŒÿbÿ5ÿÿÿ!ÿGÿ„ÿÚÿ:·=ÉSÓDŸ×õç´_ÝA†¹æÿ ÿ,þhý¬üüŸûUû/û9ûhûÀû>üÒüý8þøþ³ÿ_÷ˆìEn„wVÜŒBó³YKJ_²æ!R‚š§”n+ÍXÕÿ>ÿ˜þõýRýÀü=üÜû‘ûxûxû­ûü‚üýÙý£þ€ÿV.þ¶QÒ#Y\@þ$•ÿ_Ë6ÃÿSÿÿ¿þŸþþ™þ¯þ×þÿ4ÿ\ÿƒÿ™ÿ¡ÿšÿ}ÿVÿÿÙþ†þ>þóý´ý‡ýkýjý…ý½ýþ‰þÿ·ÿ`Ù‡3Â8Œ¹¿›OÞK Ø4vÿªþÿýbýéüŽüZüEüVü‚üÉü)ý•ýþ…þòþdÿ½ÿ;fu{nY?! ÿÿ*WžíM³€ß'd}‚a À?¤ô/tÿ¡þåý&ý‹üü ûgûJûdû•ûúûsüý¸ýsþ/ÿëÿ”3À4†ÂÚÛÀ’S ¹p 毊unsˆ›½ÑêñëØ§pÀÿFÿÈþAþ½ý=ýÌüiü&üøûôû üJü«ü)ýÌý{þFÿܤd šQutL›!ŒðN­”ÿÿ·þdþ5þþþþ/þRþwþ¥þÅþêþùþÿÿíþÓþ«þþXþ-þþúý÷ýþ0þpþÇþ3ÿ¹ÿ;ß|¹>·IeV%ÐWÅY‘Íÿ ÿKþ¤ýýžüPüüüüNü•üõüfýÜý`þÖþQÿºÿ [‘¼ÐÙ×ʽ¬¢ §¸ÞBÇ PŠ·Ó×ÕJåhÒ.†ÿÏþþlýÔüHüâûûoûbûûËû=üºü]ýþÆþÿ8äŽä"AC-ÿÆu(Í}0ç´jRLLOWWTF+ÖÿŽÿ@ÿÛþþþ±ýKýüü»üüü‹üµüÿüfýèýƒþ0ÿéÿ¢_¿XÐ+hys;ò~eÌ€æÿWÿØþjþþÙý³ý£ý¨ý¼ýÜýþ6þ`þ‘þ®þÐþßþêþèþâþÔþÇþ»þµþ¶þÈþáþÿSÿªÿvôzþ„új½ûýºUÝ<™Ö[ÿ¡þîýQýÊüaüüìûáûüû+ü~üàüTý×ýXþàþ^ÿÕÿ5Õ 1BOGC4+ #1Jc‹°Ûü*1"üÇuœ‡ÿçþLþ¬ý!ý›ü3üáû¬û›û§ûÛû,üœü(ýÅývþ/ÿéÿšDämÛ4g‡‚j8ô¡Eæ‚*χDïÿØÿ¼ÿµÿ¤ÿŸÿÿ€ÿgÿCÿÿßþªþ]þþÍý†ýJýýôüâüêü ýEý›ýþ‹þÿÆÿfÇj~ê/ZbD¯BµxÒ+”ÿÿ€þþ¾ýýWýHýKýbý†ýµýëý$þ\þ“þ¿þìþÿ"ÿ4ÿ@ÿKÿSÿ`ÿrÿŒÿ±ÿàÿ]¹~çP´W•±½¦t(»;¡úF˜ÿßþ1þýý‰ü0üðû×ûØûúû;ü‘üÿü{ýþþ$ÿ¥ÿ#‘úG‹ºÖéçäÕŵ¢‘––¤­¸ÅÁë] Ìmˆÿ ÿ{þýýrýý—üKüüòûøûüTü²ü)ý³ýZþÿ¹ÿb¶KÆ/y¥»­ŒR¬?Ùf™>÷ÿ±ÿzÿNÿ,ÿÿÿþòþâþÖþÂþ­þþoþGþþòýÆýžý~ýiý`ýjý„ýµýùýVþÀþCÿÏÿ^üš1À>¦õ*<4 ¾_ÝT± bÆÿ&ÿ“þþ£ýUýýîüßüäüý(ýbý¢ýâý1þlþ·þêþ%ÿMÿyÿ’ÿ¸ÿÇÿìÿûÿ@p§ã+uÄb§æ29,Äoý|æG¦ÿÿþUþºý,ý°üNü üÚûÖûáûü^üÅü6ýÃýKþæþvÿ„þg¾6Vdf\E/ òÒº }oaQ?%ÜŸcÃÿ\ÿóþþþ¤ý>ýäüšüeüEü@üVüˆüÒü=ý¶ýJþéþ‘ÿ7ãˆ$§"q¿ÖæÎ£^ ¢5»GÎa¥ÿYÿÿßþºþ–þ…þuþjþdþ\þSþLþ<þ-þ þ þÿýðýëýïýþýþFþþÊþ*ÿÿ‚ “™q¾÷ï¸_ònÚ;‘öÿLÿ¸þ#þ®ýDýôüÀüœüšü¦üÌüÿüAýŒýàý5þˆþÞþ&ÿqÿ¬ÿçÿ 6a|¦Ãé;m¡Õ CrŸ½ÓÔÉ¥o&ÄUÒC¶ÿÿƒþèýdýæüü4üüûçûèûüGü¡ü ý‹ýþ¬þ@ÿÜÿ_ìaÌ$d˜¯¼µ¡ƒ\-ΠsH!ýÚ¶”jB ãÿ›ÿ[ÿÿ´þ_þþ¯ý[ýý×ü©üü‰üœüÄüý]ýÑýMþäþ{ÿº_÷€þ[®×óçËAànøuöwšÿ4ÿáþ•þ_þ0þþýýôýðýôý÷ýþþþþþ%þ0þ;þPþeþˆþ³þèþ-ÿyÿÕÿ0›…øjÐ*t¨ÆÎ¶‹=ãfåJ­ oÿÓþAþ»ýMýðü«üƒüjüxü‹üÃüýüSý¨ý þmþÒþ5ÿÿäÿ*k«Û2Ps¬Íç %D^s‚†‚lLÖ€ ©2°ÿ(ÿþþ”ýýºükü0üüü"üUüüýtýüý‰þ$ÿ»ÿKÚ_Ø:Ëö  ýݶ}FÅ€CÌ—_5Þÿ¨ÿyÿ?ÿ ÿÉþŒþIþþÈý†ýUý#ýýñüíüý#ýaýªýþ}þÿŽÿ¶KàgÞH•ÍîíÙ§`—™ˆÿÿ´þTþþÑý­ý‹ýý|ý‚ý”ý¦ý¿ýÞýóýþ0þUþtþ’þÀþãþÿOÿ†ÿÖÿnÃ)…ìF ì+]w€pH µMÏH¯‚ÿæþXþÌýZýôü§üpüTüLücüˆüÆüýpýÔýDþ®þ$ÿŠÿöÿG é*cµÒèÿ !/2894)ùÔ£a¾[øÿƒÿ ÿþþ¡ý:ýÚü”üWü;ü-üBügü®üýtýìý{þÿ§ÿ8ÍXÜJ©ô)JTL/ÌŒ?óžOÿ¯k$ïÿ¶ÿ|ÿJÿÿçþµþ‡þWþ%þûýÉý¥ýýcýPýIýMýaý‰ý¸ýþWþ¿þ5ÿ¯ÿ3·IÎLÅ"|¯ÚßÔªn³7¸-Ÿ—ÿÿ¥þ9þçýýnýEý5ý1ý7ýQýký“ý½ýïýþSþ‚þ¹þëþ"ÿUÿÿÇÿ>„Ëf¸Q•Ö-@D6؉(º6±’ÿùþjþåýjýý®üsüGü?üDügüžüæüCý§ýþ‘þÿ…ÿòÿ[½f¥Ý&:KLQJ@7$ýÝ—m3ø¯a °ÿOÿãþ{þþ¬ýVýþüÁüŒülühümü˜üÌüýƒýõý}þÿžÿ*½OÐK¬=lw{]:ú¸a ­GîŠ5çÿœÿQÿÿÙþ¡þwþIþ!þþÜýÄý©ý”ý‚ýzývý{ýŽý§ýÓýþKþšþûþaÿÖÿEÁF¹;œPж¿»™b´EÃ@­$›ÿÿœþ,þÍý|ý>ýýøüöüúüý9ýbýý×ýþ^þ þèþ*ÿoÿ°ÿòÿ'j£ì"k¤ç ]‹½Üõûë‘Dð„ …ÿýþsþñý{ýý»üüNüAü?ü`ü‹üØü)ý–ýþ‚þÿ‚ÿþÿoáF£ì0^„™¥¥œtW8齌[ æ£_ËÿtÿÿÂþhþþ¼ýlý)ýïüÇü¬ü¤ü²üÐüýOý«ýþþÿ£ÿ,¾GÍF­Jw”~\Ú€"½Näx»ÿZÿ ÿ¿þþGþþñýÌý·ýžý”ýŠý…ýŠýýŸýµýÑýøý(þaþ¤þôþGÿ¬ÿxäYÆ2”ë2nŒ£—J©=Ä=µ# ÿÿ’þþ´ý^ýýåüÁü¸ü¼üÑüûü(ýlý¯ýþýOþ¢þöþLÿ™ÿíÿ)u·ú6r¨Ü9c†ž·»À°—o8ó¡?Ö]îÿiÿíþhþõý€ý"ýËüü^üLüIücüüÑü$ýˆýýývþúþ€ÿýÿòjÄ%d¢Æâêë×ÁžqE Ô˜VÒG½ÿpÿ#ÿÔþ‡þ:þðý«ýmý4ý ýçüÝü×üèü ý;ý„ý×ý@þ®þ0ÿ³ÿ5ÀFÊA©KŸ£™u=øžAÏaêuÿ;ÿÚþŒþ=þþÍý¬ý‹ýyýoýjýtýzý“ý¥ýÊýéýþFþƒþ¾þ ÿPÿ¬ÿúÿ[¸ä@˜áRmr\&è)·2°žÿÿþþ¨ýLýþüÇü ü“üŽü­üÈü ýDý–ýêýIþ¦þ ÿiÿÉÿn O’Ãú$Kj„–£¨Ÿ˜w^&ô¨\ýš/ÀÿQÿÕþcþôý‰ý1ýáü£üzü^ücüpü ü×ü+ýŒýøýxþôþ€ÿ€uâ?ŒÌõè»…LÀr%Ö‰5ùÿ¡ÿ^ÿ ÿÇþ€þ;þüý¾ý‹ýXý5ýýýþüýý?ýxý»ý þqþÙþUÿÏÿIÎMÎ=§ÿH|ž¥Ÿ|J«MØièpúÿ‰ÿÿ²þTþþÁýý`ýHý5ý3ý6ýJý^ý‚ý§ýÔý þ?þþÂþÿWÿ¤ÿøÿDžöR¨ýN•Ö2DRA*÷¸e–™ÿ ÿ„þþŸý@ýòü·üŒü{üwüü´üëü2ýƒýâýGþ°þÿˆÿòÿP° Z§ã"Hvަ´µ¶¦–xR'ì°b¸XüÿŽÿ&ÿµþNþçýŠý7ýïü¸ü‘ü|ü|üŽü·üïü@ý™ý þ|þÿ„ÿ‹ ‡÷Y«ñ@LI2ݤ\»b ¬Uÿÿ®ÿ\ÿ ÿÄþvþ<þúýÉý•ýoýJý7ý#ý!ý%ý9ýWýƒý¾ýþVþ³þÿŽÿûÿuígÝG­ÿFw˜£™{G¬MÙbäbëÿoÿøþ‰þ&þÐý…ýNýýýõüôüýý;ýhý›ýÙýþcþ§þøþIÿ˜ÿóÿ7“ä:‹Ù#g¢Öü''øÂ‡2Õkõwÿÿyÿùþyþþ–ý:ýèü®üƒükümüzü¤üÚü ýxýÖýCþ±þ(ÿ˜ÿqÞ?–æ*`‘°ÉÔ×ÎÀ¢†T)ì©fÂc­ÿJÿãþ…þþËýsý.ýîüÁüŸü’ü•ü©üÓü ý[ý³ý"þþÿ‘ÿ–!— pÇ Cbun[5Ào»\õ,ÐÿvÿÿÈþxþ2þôý¼ýýiýFý8ý&ý)ý/ýCýaýŠý½ýýýEþœþôþ_ÿÆÿ0 …ôV±?o‹•‰n:ø¥>ÒWÙVÛÿYÿáþkþþ¨ý[ýýîüÓüÃüÈü×üøü ýZý—ýàý.þþØþ0ÿŒÿäÿ9Žè:ŒÔ W—Ãç  ö˘R¥:ÊPÝÿ`ÿÞþjþòýŽý/ýäü¦ü}üfücüvü˜üÒüýrýÏýDþ±þ2ÿ¦ÿgÈ`žÉëüúðÍ®xGÁt!ÏqÂÿaÿÿ£þLþòý¦ý\ýýîüÆü²ü©ü´üÍüúü4ý‚ýÜýDþ¶þ5ÿ°ÿ2¯7¬!ƒÝ$X}ŒˆuJÏzºJâlÿ9ÿÖþ~þ+þæý¦ýtýIý+ýýý ýý+ýPýxý¬ýíý.þ„þ×þ:ÿœÿh×B«k¿?d‚yW&ãŽ/»GÇAËÿBÿÌþOþëý‡ý;ýøüÈü­ü›ü¥ü²üÜü ýIýýãý9þ›þøþ`ÿÁÿ~Ø7…Ø\•Àç ÷Ì cÆhþ‘­ÿ2ÿ»þHþÛýxý ýÚüü|ü`üeüsüüÑüýrýÚýIþÁþ=ÿÀÿ1±%’ùP˜Û(47,<ó¢Jñ5ÖÿÿÿÁþbþþÂý{ý@ý ýçüÇüÀü½üÒüñü"ýaý°ý þsþãþ\ÿÛÿRÒQÇ5œí7i›š€YÔ´=ÍPéÿqÿÿžþ?þíý¡ýdý1ýýðüëüãüôüý*ýYýýÍýþdþÃþÿÿæÿC°~ß:×FeyvdD Êp ,¨*¬ÿ+ÿ­þ6þÊýjýý×ü¥ü‡üzü~ü—ü¹üöü4ý†ýáý>þ«þÿ€ÿïÿN¸vÏ`›Êóú߯u2áˆ(¿MèÿpÿýþŒþþ¹ý^ý ýÉü™üsügügü}ü¤üàü'ý…ýçý[þÕþUÿÕÿQÌJ¹#|Ê 5YbeP4΃;à†$¾Yùÿ•ÿ/ÿÏþqþþÍý…ýHýýìüÏü¿ü¿üÈüèü ýIýŠýÞý=þ£þÿŒÿ{ýpëN´F{˜ª¢‰`"Ø~©1¶;ÆÿNÿÛþlþ þ±ýhý*ýöüÕü¿üºüÁüÖüøü#ý_ýžýìý@þ˜þüþ[ÿÉÿ$‘ø`¾n½ø1RmuiU'ð¥Oìy€ †ÿ ÿŠþþ­ýGýÿü³üügüaüeü~ü¨üäü*ýƒýàýJþºþ+ÿ¥ÿ ƒîZ¸`¤Ü'8>5!Ò™V±Mìy¡ÿ5ÿÀþWþîý’ý:ýõü¶üŒürüfüoü‡üµüñü>ýšýþwþïþrÿóÿpðjâD©ñ4c|…sL׌.Öi‘"½ÿRÿçþ„þ'þÒý†ýDý ýâüÁü³ü«ü¸üÍüõü)ýfý¸ý þsþÛþOÿÅÿ9³+£xÏ!Z¥±©Š`Òr“"›¥ÿ(ÿ²þ=þÜý|ý2ýòüÀü¡üŽüŽüšü¹üáüý\ýªýþ_þÃþ-ÿ™ÿjÚA§]¦ï!Mjuuc>̃"¾KÕTÞÿ\ÿÜþcþðý„ý-ý×üžüoüPüKüRümü ü×ü)ý‚ýçýYþÌþGÿÅÿ4³!–ôU¢åB_heT4Љ:ä~¬:Ôÿ]ÿîþþþµý_ý ýÒüœüyüiüaüvü’üÇüýZý¶ý$þ•þÿ”ÿ•‘mÐ]„¦®¤_,ߎ-ÂYÜo÷ÿ‰ÿÿ¦þ?þÝýŽý?ýýÒü¬ü—ü’ü’ü¯üÌüý?ý‡ýàý?þ¨þÿÿzòiÚD¤ú>zœ¹¶®ˆZÂcõ}€ÿÿþ†þþ©ýNýýü¿üüpü`üeüvü™üÍü ýZý®ýþxþêþZÿÏÿ=®"ˆôI¤ç%Usˆ‰|`4ú¯\öŽž§ÿ%ÿªþ/þÄýZýý¸ü~üTü=ü9üDüfü—üÚü+ý‹ýôýlþâþgÿåÿ_ÞVÈ4Œã!Y{””ŽqGɃÂUãpÿÿ‰ÿÿ¢þ5þÑýrý"ýÚü¤üyü^üXüZüxü›üÛüý{ýØýLþÃþAÿÄÿAÄFÂ0žõDªÅËÀ£s6çŒ&µ?ÄBÓÿNÿÜþeþýýœýDýÿü¾ü–ütügüiüxü˜üÈüýOý£ýþpþÚþZÿËÿE¼9¬Û(i˜¹ÇÁ°ƒP¯FØ]ÞXÚÿWÿÐþYþàýyýýÍüü]üFü5üBüUü‚ü¸üýUý¸ý þ•þ ÿ‰ÿþÿxñe×:™ç/a¢«¤‰g)ê‘7È[Ûaçÿeÿåþlþóýý&ý×üü\ü8ü&ü'ü;ü`ü—üàü5ýšý þþÿ†ÿ‰ ‰þkÇZ“²Äư•\#Îy¦+·6ÂÿFÿËþXþêý‡ý*ýáüŸünüOü=ü>üOüuü¢üìü7ý›ýþxþôþxÿûÿyüõiË%m¥ÎáæÓ²~9æ…¤!¤¡ÿÿžþ-þ·ý\ýþü»üüUü>ü3ü@üWüƒüºüýYýºý&þ™þÿ”ÿ Œ „ûdÈe™Æ×àÒ²„Að•&³4¯)¨ÿ"ÿžþ"þ­ýFýèüŸü]ü6üüüü?ügü­üøüVý¾ý1þ«þ-ÿ°ÿ*±-ªƒâ1p§ÂÚÒÅ¡l-×}œ&Ÿ"¡ÿÿ¡þþ·ýFýðüŸüaü5üüüü4ü]ü¡üéüIý³ý'þ§þ)ÿ±ÿ5¸E¼9¡U”ÉäôïÕ°t+ÒqýŠ…ƒÿýþþþ˜ý5ýÜü”üZü0üüüü:ügü§üôüQý»ý*þ­þ(ÿ·ÿ0¼@¾:¡ V Ïóü黈6áxŒ‚øÿuÿêþjþîýýýÅüxüDüüüüü6ümü«üý_ýÏýBþÄþEÿÎÿOÒYÓK´a¥Õôûä¹€3Ùsþ„uöÿiÿãþ]þãýoý ý°ühü.üüòûñûü%ü\üŸüùüYýÌýEþÊþOÿÜÿ_çpîbÒ+»ìí¾€1ÔiôwïhåÿYÿÒþRþÐýiýûüªü_ü+üüôûìûü&ü\ü¥üùü`ýÏýMþÌþZÿàÿjðzøpÛ:‹Çúö†1ÓeìjäTÑÿEÿ¶þ9þ¶ýJýäüŒüHüüïûßûâûøûü]ü¤üýjýÜý^þàþlÿúÿ ’‡ñLœÙ'þʼn2ÔbìgßRËÿ>ÿ²þ-þ±ý=ýÙüü8üüÝûÐûÓûæûüJüüöüdýÚý\þåþrÿ‹£&› _¶ê-/!üÈ,ÂSÕQÇ7°ÿ&ÿ™þþœý+ýÌütü3üþûÝûÑûÔûíûüQü¦üüülýáýcþíþ|ÿ—$±3¬xÇ/GH9Ü“8ÍWÖJº'šÿ ÿyþùývý ý¥üRüüâûÄû¾ûÄûæûüYü¥üývýôýwþþþ‘ÿ§4º>°yÅ+BF5Ù˜7ÖZÞPÁ+Ÿÿ ÿ{þíýrýùü•ü?üûûÈû¬û û°ûÌûüGü üý}ýüýŠþÿ¯ÿ8Ï\êdà@žâ<LG3Ì!ºAÁ8©Œÿýþjþêýhýöü“ü:üøûÅû¢ûûžûÄûíû6ü‹üòühýèýxþ ÿ¤ÿ5Ðgö~ôj¼@gtoQ%Þ'´6¬†bÿÙþFþÆýLýÞüü.ü÷ûÂû´û¤ûºûÔû üMü¨üýýùý†þÿ§ÿ9ÊcïsôZÁ Gq€h8ü£?ËC»ˆîÿRÿ¹þ þ›ýý§üHüöû¾û“ûû„û—ûÈûÿûTü°ü!ý›ý"þ®þ@ÿÙÿaü…‘oÀ<irsX.í¡<ÍOÃ3šÿÿiÿËþ6þ¥ý#ý¨üCüêû¨ûyû`û\ûqû˜ûÚû)üüý†ýþ®þJÿïÿ¸AÈ:žô5b{ƒoRÐz‘mÜÿGÿ²þ$þžýý±üJüþû¶ûûoûmû|ûûÛû"ü…üõürýþ”þ5ÿ×ÿt´MÔ[¿'f¢¸Â±ˆPúš%¢|ã@­ÿ ÿxþâý`ýäü}üüÙû ûûpûvûû¹ûúûIü©üý“ýþ­þBÿÝÿq ¤2¼8¥MªÁ´˜d»LÉ=ŸR¹ÿ ÿkþÌý;ý¸üFüäû™ûbû=û;ûAûhû ûéûMü¹ü8ýÀýVþêþŽÿ½Wærð`ÄWŸ¡–t=÷œ0¹0ŸeÈÿ'ÿ…þåýWýÉüUüæû•ûMû'û ûû+ûdû§û üyüýý/þÕþÿ$Òw«3© `™ÂÐʯ}9âyø\È'”ÿüþ_þÕýKýÑüdüü·û}ûRûDû>û]û‚ûÈûü‚üúü„ýþ¸þ_ÿ±W.³!€ÆùóÃw¥$’ïQ›ÿÿMÿ©þþrýëürü ü´ûsûEû/û,û@ûdû¡ûîûKü¼ü4ý¾ýOþéþ…ÿ¾_÷‹üY¡Ø÷ÿóË=ÕYÏ1ŽÛ(~ÿÄþþsýÛüSüÛûxû/û÷úáúÙúöúûkûÄû2ü¶ü@ýÞýþ%ÿÒÿq¸IÚSà h¥ÂØË¹…Hñ”kÉ%‚ÿÜþ4þ—ýýüyüùû“û<ûÿúÑúËúÉúøú*û…ûëûnüýüžýMþÿþ¿ÿl+Úˆ²$Ú11 ÷±aññaÂ{Ùÿ8ÿ‘þüýfýãühüü¥û`û+û ûû û0ûaû¯û ü€üüü”ý-þÙþ†ÿ5åžEì‚ }Ü"Sf^>­B¾.†Ý gµÿ÷þHþžýþüyü÷û—ûAû ûãúßúãú û>ûŒûëûWüÙü`ý÷ý—þ5ÿáÿ|"Æ]ôvòY±õ">:(õ´SåZÇm°úÿ7ÿxþ¾ýýmüáû`ûû¯ú…újútú•úÏú(û’ûü§üMýôý±þeÿÐ,ÆXÓ@˜Ü "%ê­]ûˆuá7”ìÿ@ÿ‘þêýFý²ü%ü®ûDûïú·úŽú…ú—ú»úû^ûÕû_üüü­ýeþ,ÿòÿµ{:ð(  Pˆ˜–t9æ}oÙ*‚Çgÿ¼þþqýâüXüçûû1ûóúÎúµúÀúÏúûBûžûü†üý²ýSþÿ¿ÿx1ïNáuåK½Ï¿šRòxçCŽÍ5pÿ¤þæý.ý‡ü÷ûtûûÂúŒútútúú¾ú ûcûÚûYüèü‹ý(þÛþ‡ÿ.á†1Æ\ÚR°;bscL ÁVÚK¨ø9u²ÿçþþ[ý¤üúûhûäúú5úúöùú.ú}úÝú^ûôû—üVýþãþ­ÿt;ü²VíiÖ)d†”d#×rÿzçL¡ö@™ÿßþ4þƒýåüLüÅûKûæú™ú]úBú;úQú†úÏú;û·ûRüùü»ý~þXÿ!ÿÑ¢^ª/™ä$èž8¿*ŠÓTŠÑÿÿPþ›ýùüaüàûkûûÉú–ú~úvúŠú³úðúEû§û&üªüIýíýþ[ÿ Ó‘Q²MÙM®î" Û‰”ï=o¡»çÿÿ&þRýüÙû@û¹úOúúÓùÂùÒùõùAú˜úû—û7üÜü’ýMþÿÍÿ†@õ¡>ÐQÁdœ±¾¥:áqêS¨ì+Z‘ÿÁþëý(ýhüºû%ûœú=úéùÆùµùÎùúZúÌú]ûü¿üŽýgþFÿ$á¬q·8 ë0(Éy “f»NˆÕÿÿRþ›ýçüEüªû#û­úJúÿùÍù²ùµùÒù úaúÏúZûøû²üuýNþ-ÿòЯv6ÖeÍ#I[B µ=²P„µÕ+ÿ[þ‘ýÚü-üœûû±ú`ú(ú úúúDúƒúÝúKûÇû_üúü¯ýeþ,ÿôÿº‡W܉0»:”ßö½gð^¯ë.:GWÿjþƒý­üìû?ûµú@úôùÂù´ùËùúùQú¹úAûÝûˆüDý þÐþ¡ÿ^)â™;ÒUÅ"c—§¬_´?°]›Ëùÿÿ/þPýhü—ûÇúúlùáøsø$øø÷î÷ øHø­ø0ùÕù”újûYüNýTþYÿSSC$ð£<·PllM¼PÏ<ší8}¾Nÿ¢þîýOý¸ü,ü´ûIûòú®ú€úcúeútúŸúäú4û©û"üºüZý þÄþ‚ÿAÿÂu!»CµOwqD§8¹)’ðP§vÿìþcþíý…ý.ýèü±üü|ü}üŠü¦üÓüýKý’ýèý@þŸþÿfÿËÿ+‹ðL¤ø<ƒ°äø éÅŽM§Kàz©ÿ1ÿÔþgþþ½ývý;ý ýèü×üËüÔüãüýü$ýPýˆý¿ýþ?þƒþÈþÿIÿ…ÿÀÿõÿLoœ±Óæù# &!úëàÏÀ²Ÿ‘p`QD6+  ÿÿÿÿûÿúÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿþÿþÿýÿýÿþÿûÿûÿýÿýÿýÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿýÿþÿþÿÿÿþÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿüÿûÿþÿÿÿÿÿýÿÿÿýÿÿÿÿÿþÿÿÿþÿþÿþÿþÿüÿýÿÿÿÿÿÿÿþÿþÿýÿýÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿüÿþÿþÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿýÿúÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿÿÿÿÿýÿþÿþÿþÿþÿüÿþÿÿÿýÿþÿÿÿþÿÿÿýÿýÿÿÿüÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿýÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿüÿûÿûÿûÿüÿþÿÿÿÿÿýÿþÿýÿüÿüÿýÿþÿþÿüÿüÿýÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿüÿüÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿýÿýÿÿÿÿÿÿÿýÿþÿþÿþÿÿÿþÿýÿýÿþÿþÿÿÿûÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿûÿþÿþÿýÿüÿþÿÿÿüÿýÿþÿþÿÿÿüÿýÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿýÿüÿþÿþÿþÿÿÿþÿüÿüÿüÿûÿþÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿþÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿþÿýÿþÿýÿÿÿþÿþÿÿÿýÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿüÿÿÿþÿþÿüÿüÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿýÿÿÿþÿÿÿÿÿÿÿüÿûÿÿÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿýÿüÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿýÿþÿÿÿýÿüÿüÿþÿÿÿÿÿýÿüÿÿÿÿÿÿÿýÿüÿþÿþÿþÿþÿÿÿÿÿüÿýÿÿÿþÿÿÿüÿûÿþÿÿÿþÿýÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿýÿýÿúÿûÿýÿþÿÿÿÿÿýÿþÿþÿþÿÿÿýÿüÿüÿþÿþÿþÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿýÿüÿýÿýÿüÿþÿýÿýÿýÿûÿüÿÿÿýÿûÿüÿýÿýÿþÿüÿÿÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿüÿüÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿýÿþÿûÿüÿþÿÿÿýÿþÿüÿûÿýÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿýÿþÿþÿýÿúÿùÿýÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿÿÿÿÿþÿýÿûÿüÿüÿýÿüÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿýÿýÿýÿûÿüÿÿÿÿÿýÿþÿýÿþÿÿÿýÿþÿþÿýÿüÿüÿýÿýÿýÿüÿþÿþÿþÿýÿþÿýÿþÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿþÿþÿýÿüÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿüÿþÿÿÿÿÿþÿýÿüÿüÿþÿýÿüÿýÿÿÿÿÿþÿüÿûÿÿÿÿÿÿÿÿÿüÿÿÿÿÿüÿþÿÿÿÿÿýÿüÿÿÿÿÿýÿÿÿÿÿþÿþÿýÿüÿüÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿüÿüÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿþÿÿÿÿÿýÿþÿþÿÿÿüÿûÿüÿýÿüÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿüÿüÿþÿþÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿþÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿýÿûÿþÿþÿþÿþÿþÿûÿüÿýÿþÿýÿÿÿþÿþÿýÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿüÿýÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÿÿÿÿÿþÿþÿÿÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿýÿþÿþÿÿÿþÿþÿþÿþÿþÿüÿüÿÿÿÿÿüÿÿÿÿÿþÿþÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿþÿýÿþÿÿÿÿÿþÿþÿþÿýÿýÿþÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿûÿÿÿþÿþÿÿÿþÿþÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿüÿýÿýÿÿÿÿÿþÿüÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿÿÿþÿþÿþÿþÿÿÿýÿýÿÿÿÿÿýÿýÿýÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿüÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿýÿþÿüÿûÿûÿýÿþÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿþÿÿÿýÿüÿþÿýÿýÿþÿÿÿýÿûÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿþÿýÿÿÿþÿÿÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿþÿþÿÿÿþÿüÿûÿþÿÿÿýÿÿÿÿÿüÿüÿþÿýÿûÿûÿüÿþÿþÿýÿþÿýÿþÿüÿüÿûÿýÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿÿÿýÿüÿþÿüÿþÿÿÿýÿþÿÿÿýÿýÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿüÿþÿþÿþÿüÿÿÿÿÿüÿÿÿÿÿþÿýÿÿÿÿÿüÿüÿýÿÿÿÿÿüÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿûÿúÿúÿýÿþÿýÿýÿþÿÿÿýÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿûÿüÿÿÿÿÿýÿÿÿÿÿûÿüÿüÿþÿþÿÿÿüÿýÿýÿýÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿýÿûÿüÿÿÿþÿþÿÿÿÿÿÿÿüÿýÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿþÿûÿüÿÿÿýÿþÿüÿýÿýÿþÿÿÿýÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿþÿþÿþÿüÿýÿÿÿþÿýÿÿÿÿÿþÿþÿûÿþÿüÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿþÿþÿþÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿüÿþÿÿÿÿÿþÿþÿÿÿýÿüÿÿÿýÿÿÿýÿûÿþÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿÿÿþÿþÿûÿýÿþÿüÿýÿþÿüÿüÿýÿüÿýÿýÿûÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿýÿýÿýÿýÿþÿÿÿýÿüÿýÿûÿûÿüÿÿÿÿÿýÿþÿüÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿýÿýÿÿÿþÿüÿüÿÿÿÿÿÿÿýÿüÿüÿþÿþÿÿÿþÿÿÿþÿþÿþÿÿÿþÿüÿýÿýÿýÿþÿÿÿþÿýÿþÿþÿÿÿþÿüÿýÿþÿüÿûÿýÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿüÿüÿýÿÿÿþÿÿÿÿÿÿÿýÿýÿÿÿýÿûÿýÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿýÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿþÿþÿýÿÿÿýÿþÿþÿþÿÿÿþÿýÿþÿÿÿÿÿþÿýÿýÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿüÿüÿýÿÿÿþÿÿÿþÿÿÿÿÿüÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿþÿüÿÿÿÿÿÿÿÿÿÿÿýÿûÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿýÿýÿýÿþÿþÿþÿýÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿüÿûÿþÿÿÿýÿýÿýÿÿÿÿÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿýÿûÿûÿÿÿþÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿþÿÿÿýÿýÿÿÿÿÿýÿüÿþÿþÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿüÿýÿþÿþÿþÿþÿÿÿÿÿÿÿýÿþÿýÿþÿüÿûÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿüÿüÿýÿÿÿÿÿÿÿþÿþÿüÿüÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿþÿýÿÿÿÿÿþÿýÿþÿýÿýÿýÿýÿþÿýÿýÿþÿþÿþÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿüÿýÿýÿþÿýÿÿÿÿÿÿÿüÿüÿþÿÿÿüÿüÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿüÿÿÿÿÿÿÿþÿÿÿýÿûÿþÿýÿýÿüÿýÿþÿÿÿÿÿþÿÿÿüÿúÿûÿþÿÿÿÿÿÿÿûÿúÿûÿýÿôÿüÿôÿûÿ÷ÿýÿùÿþÿ ûÿôÿíÿäÿÞÿÚÿÙÿÓÿÜÿÙÿèÿìÿüÿÿÿ.7GLSSLE5! ÷ÿÜÿÀÿ ÿŽÿpÿkÿ]ÿdÿmÿÿ¢ÿÉÿöÿ#V‘Áñ*5(á¤Tÿ6ÿÏþpþ!þåýÀý¾ýÛýþ~þÿžÿQ Ö9Ã!J:åQ|j.Ñþdýïûúuù•øøõ÷Wø0ù‹úXüþ·s o S ¤1ë· › À<Vû'öñYì\ècå¸ãžã1å‘è¬ígôƒü™K7",)-\0(1À/,#%^m (ù>æ…Ô>Ç`¾%·<±í¬lªß©4«®ë³}»øÄÔ2ê·‡®-y:BpGõJ€LLáIFÛ@6:300$ŸCùÊîç`â¼àâüåì£ó üzL ´'5[Ž :øžêܯÐÇ™ÀÖ»a¸‡¶k¶9¸ë»pÁLÊØít‰*0±=‚FÞMwSWoXšWT•OÇH@W5Ö$í \÷)âDÒrÇ:Á{½‘»p»ù¼ý¿dÄjËZԔ߃ìIøF÷ 7“R È‚$øXïÞæ{ß?Ú××BÙzÞlçBótг" 0ú:BÞGBLùNÌO›NfK1F=#G.³7>ŠB¾EjG`G‹EéAƒ<ñ2E%½‡úÇãѱÃu»•´l¯¬áª©«„®9³ª¹rÁÔ̶Üfò‘`)+l51<©?eAsAú?=[81¸(šæ[þÙ÷šóòûòWö²û‰] o— %$'ú&O$;W lûæëšÛFÏ'žU¹wµ4³º²&´p·¼TûΠßxõ– ~#¥3¹>FéKÞOßQÛQßOL¦Fë?7*!Q¿óäÞ×™ÐÔËfÉ8ÉËÉÎßÓžÚ°ãíÄõ0ýÀ&œ¼Òû8ôëUâÞÙ²ÓBÏSÌGËX̨Ï=Õ±Þìžü@¹ {/ë:FBHHÖLÇOßP PEM›H>Bè9s,î+œë×YÉŒÀ‹º@¶È³2³l´[·Ä»aÁ É#ÔQâ0òôì «´ %|''®$Ú\ñW %ý‹øöâõ+øÛü»€ §!ã*2B8.<;>á>>k;(6§-k!Ý¥ütè¬Õ5Èl¿¥¸T³­¯ç­®:°?´ü¹+Á¨Ë©ÚËï9Äå*C6¢=B·D¼EEóBw?:ü2ú)>•§ûÖónîšëCëEí;ñ²öýÐ< Á»ÒŽÓ‹ ×ü~ðÂã~×9ÎUÆÁ½»=ºùºo½ŠÁ#ÈÓìâ÷@ |!f1ï<3D J=NPQ£OeLwG'A9ˆ,“hõ2äWÖÇÍŽÇ@ÄþÂQÃKÅàÈÎ9ÕÇÝþç‰ñÔù_á&ãÄ(û‡ôrí•æˆàïÛ±ÙWÙ;Ûà½çÿñwþ— â)*Ò4=BÕFÀI K–JbHeDÖ>g6§)ˆ;¸ëÎ×%ÊÁк,¶D³)²à²NµR¹«¾sÅêÏâÜÿífþe sÒ$+s.È/:/õ,=) #Ká yuXþ9ýHþev Ò%(+‘/­2)4º371–,"%o úµèä׫ËuÂN¼]·ä³² ²Ó³^·‹¼)ÃãÍvÜñÝ+>+ö6j>LCFHñG:FC¬>”8v/Ë$ÔW ;ýåòÌê&åâjáã‘æ…ëdñ‘÷{ýŒM\eCø¯û–ó&êß߇ւÏLÉş°ÁÂ"Ä[È×ÏðÙƒé[û=s!(0K;UBãGLkNOìMKrFy@„8*,!o?ô=âDÔÛʆÄÁl¿.¿lÀÝÂÇpÍðÔ`Þsé¬óŸü¾äØ › V HÝŽþâø^ó©î=ëŽéùé©ì»ñùhq ¤ü%j/²7G=A’CÁDrD‹B?›9S0Ö#jàýìéb׀ʋÁr»Ø¶Ð³‘²³Gµ¹M¾òÄOÏ`ÜîXÿwÝí(/4’6ù6ˆ5w2.µ(h!$ ˜Åçþÿ¹Ü ÕBví!¶%®'Û'ù%!'M]Ñöè‹Ù¦Î¯ÅÑ¿m»G¸ ¶‹¶'¸Z»$ÀôÆ Òrá'õF  -o8„?hDÆGxI…IïGãD„@Ò:ù1>'Ë hüVðUæ¶Þ Úñ×ÝדÙëÜâè]îRôvùTý”ÿwþûñõeïêçèß¼ØJÓ&Ï4ÌÕÊ8ËŽÍáÑØSãñ†"./™9W@vE?IKLK5HÖC >G5Þ(î{dðOÞdÑÜǨ¾°¼A¼D½—¿ÃfÈ4Ð Ùžä^ðûV¿ ÿùè)) ]V—þ úâ÷Âö„÷>úÿ‘Î .N!+*ù0 7;Ž=‘>P>¤<ê8Y2)£Î ÉøUæ£ÕÌÉŒÁà»·Á´£³/´p¶:ºm¿OÆÑßñ¼{—"í,4ó8d;4%CqFVH²HxG¤DY@::M0"#¸ÂýëÙÙ$Î]Å$À«¼¯º.º.»‚½Á(ÆáÍýÖ?ãPð~üNTPòf^$YZ ¿òX@Û6Mç Âq‚#* /)36c7ó6¦4[00*% ’Lÿò6âòÓ.ÉÊÁ®¼Î¸c¶„µ?¶‘¸a¼ŠÁÉ2Ô{ã„õZj4'÷0O8­<Ó>? ?F=ù9Ô41.y&xW ~\û÷šôô õž÷û-ÿP Ó  m èzWúªñäç~Ý×ÔêÍâÇà×Á‡À·ÀU®źËHÔÎà*ñv¤%Ø1C;ApEcHÎIªIñGÁD:@%:£0È$Š6³ô–æ­ÚÓ ÎÚÊšÉÊ6Ì ÏÔ½Ù÷à“èŽïˆõú(ýzþ+þOü.ùõ€ðÙë›çNäOââÇã§ç¯íËõ·ÿ …I$.]6´7K-ÔøQþXîÕßðÔÐÍzÈÁÅĸijÆêɸÎWÔBÛíãnì ôzú]ÿújÉÿKü…øÓô¹ñ¢ïÝîÌï~ò÷‚ýƒß2è#U,S3'9=H?j@H@Ñ>Û;~6).!#%†ð5ßëÑÎÇZÁû¼í¹d¸U¸Ë¹¼´À\ÆϳÙ"è ÷"<í%O+U.³/r/Ë-ü*Ñ&`! ësÿ Ú1r" â T ›{Y"²#G#Ù E”â jœöÆé’ÜgÒèɒß¿¿¼*»ïº.¼Ö¾ßÂÉ[Óààò±2r%¦0=9‡>×AÍCTDrCPAû=9¢1ú(J¯Åúëð£éfäFá àÖàãjæ{êÚîó‘ö/ùúrúÕøÈõcññë½å;ßfÙÚÔ“ÑOÏjÎÏUÑTÕÜqæØò·”Ò·+w5Á<[AÏDêF•GÃFuDÈ@·;b3¤(%5i÷_çRÙôϸÈ]Ä Â6ÁšÁ2ÃOÆ"ËhÑŸØ âÞëõïüi5J š \ Ä -÷’rþóûwúLú¦û þ.K © æ!°)•/Í4¶8ù:ì;u;j9m5/&R )ú˜éÌٓγÅ!À+¼…¹R¸¸Yºz½ÑÁȰјÝHíàü» Tì$n,t1®4'6Ü54ü0í,Í'G!é %´»H5UQÚ Õséë4 # Õñû»ñŸæSÛžÒ?˃ÅËÁ¿\¾ˆ¾ÀäÂÙÇöÏTÚœéFú] 4—*¢4<@ŸCLEE_DçA<>ç8Î0-'!} ŽÿËóžékázÛHØÝÖ)×ÙØÂÛ àå êÀîºòªõ[÷©÷‹öôwðìçùáIÝæÙ»×êÖ´×DÚ$ß›æðGûÆ/ã"x-+6Œ<@yCEcE6D­AÌ=Ó7a.7"ªœÌï½ß“ÓÎʱÄ,Á3¿¾8¿Á"ÄÉÐí×_â‡íõ÷B ?¿ôàò€ û Öd ÷[>‹ ˜¶•%+T/«2Õ4‹5¡4ÿ1™-'ØèæòãçÕÌbÄ’¿ ¼Ü¹ ¹µ¹Ã»7¿æÃ¤Ë³Õíãô"r^!…+S2i7:;®:ø8Î5&1½+%¾pä cG´ý¯û+ûüñýž¬´J  ” © ,÷1þæöjîåŠÛÔÊÍaÈøÄáÂ*ÂÂ{Ä(ÈzΤÖ!ãUònë#á.:84>1BåD4F F†D£Aš=“7Š.´#˜ßøSì‚áDÙ7ÔCÑïÏÐÑ;ÔØõÜãéƒî órösøùRøZödóÅïåë&èüäÐâöáÉâgåýéxð½ø„‚ M % .¢5b;ÿ>dA–B{B AD>©92@(¸; \ø¼ç³ØuÎyƧÁ¾÷¼¦¼°½ê¿FÃyÈ#ÐåØäçð…üC‹Ø6!Ð ôé+› ÷ t@h õ ®lÎtÂ$Í( +>-©-›,*0%bBteúƒìdÞ/ÓFʟÿ€¼Éºfºw»æ½ªÁZÇXЦۘëüJ ¯£('1Ò7»;Æ=r>í=E<94á-¦&<†{ Œü÷Åó#òò0óRõøûÝý Tm&gý3ù¡óòìyåÝÄÖÑͥɨÇ#ÇõÇ­ÊFÏÕ`ßìûu )~(¥2¬:³?9CpEGF®E·Cm@ò;4+#èØÿzñoä˜Ù­ÒÞÍßʆÉèɲËÏÎÛÒÛ×HÞ•å{ìò‡÷.ûbý.þ¢ýÿû…ùöŒóÌðÎîÏí3îðºóù÷ÿG¹ìè%©-34s9å<Æ>’??b=ã9â3²+á–\éïÕßDÓíÉaÃt¿Ó¼}»Š»î¼Œ¿SÃ8É Ñ’ÛóèLöèa@: À%Ø(&*ê)G(z%x!Ÿ¡þüþ )   m g t;u¶—­"s$É$—#E ä‘d ·ÿÒó6ç¶Ú[ÑdÉ«Ã!À³½}¼›¼¾ÚÀ6ÅjÌÛÕ™ã°ó!L‘#2.]6Û;ç> @ý@"@>»:u5w.I&‘‡: ýOõ6ïðêoè£çJè-êßìðKó=ö~øËùçù©ø öBò[íçTá)Û2Ö‘ÒÌÏ-ÎåÍ*ÏÒªÖcÞ8éÄõ~ù” X,h5.<\@YCE€E‚D(B>!9¤0& Cº÷éÄÛâÒxÌäÇ›ÅÇÄ\Å7ÇšÊ\ÏàÔ³Û?ä†ìôú›ÿ>a"•¹ÿ†üPúîø–øšùü”b LÝr%),¿1q6’9M;¼;Â:L8˜3-õ#‡¼1øeè—ÙϳÆiÁÕ½˜»¨º)»ü¼ÀrÄqË„Ôàúî(ýŠ ª!(-Á/è0‡0ê.+,p(“#x„ƒ  Ùø^çZ j´å~8¡‡­ý‹ góøbî<ã¯Ø¼ÐàÉÙijÁÇ¿¿¿GÁ|ÄÊTÒ-Ýlì}üÌ µ9*y3Ž:Î>wAÈBËB}A?B;\5‡-C$íÔ d<ö‚íæ|á^Þ Ý“Ýsßnâæêúípñ ô¦õÿõõæòœïcë¢æžáÜÜJÙ´ÖyÕÕ×qÚFàè‚ò þ¢ æ%¹.ó6° Ù¦Yù4î¹ä Ý`جսÔ"Õ¾Ö§Ù–Ýâˆç5ì>ðOó9õæõQõ—óíðŽíÜé)æââ_à ß-ßá»äYêÈñäúRÆÈö'B0Œ7{<Ž?ˆAMBÌAõ?Þ<¡7S/ñ$ûökæ•Ø4ÏÀÇ'ÖÀI¿A¿pÀ»Â”ÆlÌ”Ó=Ü€çqò¬üªH .Q±^¤´þ • T9X » MÝ0äw$æ(,X.b/*/n-&*$—Ìh÷é^Û?ÑÍÈ ÃY¿Í¼ˆ»’»½µ¿«Ã>Ê_ÓjßÉîTþ «¢'r/^5(9;†;:€8Ã4È/*Æ" ²' ·§þûÚøøø ú"ü”þèÚ$÷kqü÷ðéápÙjÓwÎVÊ“ÇOÆYÆ¿Ç ËfÐw×qâøï¢þÐ 6*‘3Þ:l?yBDD¶DÍC˜A2>981©'c (þñVå‚Û!Õ/ÑÙÎÎÁÎªÐ¥Ó’×£ÜØâàèOîìònö´ø­ùnùøæõ1óBð‰ífë'ê0ê­ëÐî¦ó!úL p )‡0×64;ð=e?¶?Ì> <„8¹1+)@ 8ýQíùÝŸÒöÉðÃlÀ9¾R½³½[¿ÂuÆÍÕŸßì0øju Þƒ.!ç#©$ $"ä» } × Ð Ñ£ñh™!é$÷&Þ'V'<%ø lùå|ü&ðaã˜×ϛǸ”¿Ž½Ê¼M½+¿AÂIÇ=Ï?Ù¡çR÷j{$%.y5q:I=‚>‰>c=÷:7B1²*b"Q­ÆþÁ÷ýòÝïHî'î6ï(ñ¬óTöÎø·úÇû½ûxúâ÷ô ï%é¯âÜ ÖÒ5ÏðÌñËlÌxÎ#Ò ×cà÷ëûøü|Ü#Z.ú6æ<ž@1C}DoDCd@<66Q-ö!’õ è ÜÔÎÁÊšÈ3È3ɬË@ϵÓ0Ù%à“çî¨ôªù`ý¹ÿ²|JÿRýõú‹ø}öõÂô¦õþ÷Öû"Õ¦Le!^)p/Ç4Õ8M;…|9¼1(8â ‰ûºìßÏÔÌÍxȇÅ!ÄÄmÅèÇ(ÌqÑ׎ßkèÒðTø¹þª7= î a íÙƒK’ÿ”þ£þíÿŒŒÕ /Wî Å'-…15\7*8©7\5Y1²+j#<“ ûì5Ý5ÒpÉXÿ½Ì»Û»7½Ù¿›ÃÑÉiÒÝVëœùXSà'D-¹0£2ú2ê1£/^,$(¾"I$ô q36m©®2 Ñ 8üÕh”! ˆ ù—ðÄæ¦ÜÔÎWȪÄeÂeÁÁæÂñÅËÒ\Ü”êÄùk ë'Ð08‡=@@B¬BÔAÂ?Ÿ<70k'².(#øgî]æ%àüÛ Ú«ÙÚ²ÜàäBè@ìÁïaòôuôÀóÞñïëŠç‰ãØßäÜ6ÛÓÚÐÛÊÞ¿ã¦êLó€ýÜp!“+q3Õ9ö=˜@B^B_A?a;5,É £éeò}ãöÖ•ÎûÇñÃàÁ ÁtÁêÂãÅmÊžÐ©× á?ëûô½ýGY Ø» ú¾¬"q /8Q¡1 ó Â]x‰$u)-ä/121z.K*¦# °Þò¾äÉ׈ÎÞÆíÁ«¾˜¼Ø»\¼F¾WÁƘÍñÖKä9óSg(Ø.Ô37€8p87)4*0j+l%ü\[? O­uþƒýÅýöþÑA8T5±¹Zûµôûì•äóÛ Õ“ÏÆÊ_ÇjŽÄ^ÅjLj˅ѦÙÎåñóä29!Ì,¢5<Ñ?\BCC3B ?Ö;´5k-6#±:bû›ïGåÂÜ<×ÿÓrÒ<ÒTÓoÕÉØÝfâ«çˆì¥ðÊóËõ”ö6ö¾ô|òšï‰ì“é'çšåCåaæ(é¢íÛóžûÁôÒ¶$-ú3‰91=N?P@!@°>ï;7i/Ì%Æfµø2é×ÚÛÐ÷ÈÎÃßÀ;¿Õ¾­¿«ÁñÄÊ(ÑbÙ[äÏïºú—/ (dÑ}•MýóšJ]. ç Ñ Ý "m>Å#('¾)ú*+Ý)Å&‹!½õ­ø¶ëŒÞþÓÅËSÅ<Á†¾½¾¼É½%À±ÃÊÉpÒ–Ý—ìü/ œ>&³.5n9Â;¦<-TAbCDCªA™>ë9™2–)Ðp8¶òdæÀÛÉÔ4ÐFÍãËÌ—ÍNÐèÓŠØfÞå^ëùðõùIû3üýûÂú×ø~öôùñ„ððÂðêòžöæûˆ q2&Y-M3F8h;2=½==;J7ú0õ(ØXÿ’ïwà\Ô˜ËÅÁ¾[½p½Ä¾LÁ&Å=Ë!ÓÝ܈éöðÇ ¾m#•&((®&L$ ^ôàSµ    M ÃÉr´+!"c" ý;YýÆñäåNÚ¥ÑKÊßÄkÁD¿D¾¾ ÀÈÂÇÏrØ)æ…õpÙ" -Ì4<:k=ú>Q?x>”<9»3'-O%¼aþ÷4ñí€ê†éçé^ë íGð ópõH÷-øø¤öôXð§ëHæàÛŒÖeÓÑîÏГѧÔÐÙ âì¡ø·t8!3,¯40;A?ÿA…C¼CªBC@»<Ø6N.¯#P÷oéÕÜ*ÔζÉIÇ†Æ ÇáÈR̽ÐäÕqÜ~ä2ì=óKù"þ—·„.êæþÈü#û6ú[ú¶ûwþ¦,F&<,A1~5j8Ï9ü9Å8Ø5ä0_*e Pöç!ÙPÏWÇB¿½R¼ä¼Ê¾ÌÁwÆ«Í_ÖâIð·ýo ߯ '+.0/ã.b-á*7'‘"÷‹e@ M …ðS ‡ 1 ¥´Ñ»+ý#¡°ÿuöUì¾áóןÐ4ʄłÂâÀ`ÀÁ÷ÆïÌÕ¿àsïéþp”9*ñ2°9Ó=<@ZAEAè?w=v9R3â+"½= hÂöîñç%ã9àüÞ^ßáµãÿæŒê÷íìðóRôlôWó$ñ÷íê åáÞÜÌÙ°×ÁÖ5×AÙ Ý|ã¹ë·õ÷B B&G/ô6Tƒ9&2ò(‚O ëüéíÜß Õ®ÍúÇÇÄÃÝÂ²ÃÆ¢ÉåÎóÔuÜëå ïx÷ÔþÙp € Y~ Ë š A$Ø0Á± áì‰=$Á)á-N1°3Ò4„4¤2!/*î!¥× ü¶í`ßíÓ1˞ĉÀϽM¼¼?½¤¿:ÃôÈkÑ¢ÛÈé;øOŒcŠ(L.T2¯45¼4´2/+_&õª qõf‹Ì ó  K / ² ²8oùuñ­ègß/׿ÐrË9ÇŸÄNÃ:ÆÄLÇTÌ5ÓŸÜ8êêø4{Ï%Ö/ý7"=T@=BéBEBn@l=Ä8œ1?)©»0søøí åÿÝvÙëÖÖ‚ÖIØÛûÞ†ã"è[ìøï¢ò;ôªôñó0ò›ïkìé­åÜâÞààÂàã@ç.íÔôüýP‡)1Ö7^<?¼@4Aj@d>Ð:Ð4…,O!v€óäž×æÎ÷Ç¢Ã\ÁLÀsÀÆÁ@ÄUÈ€ÎzÕ–Þ[éËómýâõ j2Qä']â =Æ  % c Ñ l ªÔB H%E) ,Ð-w.Ì-²+Ë'T! 5 øÜóNæuÙÐ0ÈþÂ¥¿}½ˆ¼á¼†¾jÁâÅÍÖ"ãò '<(x/è4o8 :E:89Ý6è2 .S(é  À¶ ½ÿÔûëùQùÑù4û"ýHÿBÁ{ „¢þUúÒô<îÝæßØ›Ò ÎbÊýÇ Ç…ÇÉ`ÍíÒ®ÚbæÑó1³+44;I?BwC˜CwB @Š<Ã6.¤$D ïû|ïtäYÛqÕêÑâÏYÏ*Ð#ÒÕ Ù:Þä¾éÉîõò öô÷Ÿø4øÊö©ôò~ï'íwë¿êFëLíàðöÚüö06‡"ý*¡1y7N;©=Æ>Â>Œ=Ó:6â.š% —ù'êžÛ_ÑGÉÕóÀ×¾>¾æ¾¾À¨ÃtȈϡסâ î5úÕ=#] À"e#†"c XÁyrG  " Mm.^ƒU"%µ&'&j#]i«mùÎìPà’Õ•ÍáÆw²¿ ¾½y¾™ÀÄÝÉ?ÒÝÛë8û‹ 7=&/Ê5<:Ì<·=…=*S:=3N*È9±ÇòïåêÚ¥ÓŸÎAË‚ÉaÉ·ÊTÍÑiÕÛ"â5é´ïVõ×ùýÿÂÿ^ÿþ&üöùÛ÷)öBõbõÊöžùäýˆy j ð#û*©0˜59';ý;l;|9¶5Ì/(ae‹ÿMðSáñÔÌLÅ)Áƒ¾$½ ½<¾œÀ6ÄûÉñÑ|Ûaèmõàg zÜá%…)6+z+™*x(I% !-hj¹ 2 Ë N Öâ wó9ýwÅüRò@çøÛcÓLÌÆÐÂ’À¿Ž¿çÀsà ÈiÏ“Ø æ6õ¼¤"$- 5ª:ô=¸?:@Œ?º=Ž:5ä.'ººNÒý›õåîÝéŽæèäÇäìåèÎêÜíÄðJóõÑõxõöóYñ¬íDéPä4ß©Ú׺ÔnÓRÓÔ[×LÜ0äéí0ù‹©ô+k3:j>1AØB3CHB@ª<ÿ6”.($Œk}÷8é;ÜbÓüÌBÈÑÅÒÄ(ÅÅÆ¿É;ÎÓÚ;â¸ê¦ò¤ùyÿæî“í2¯§…–<ÿºþBÿ(–-·ïk#¥)c.s2‚5X7µ7†6«3 /ï(¦ßeö²çÛÙýÏåÇŸÂO¿&½M¼¾¼|¾gÁáÅãÌÕ°áªïŽý¹ ÉM!ã(Œ-‡0ò1ë1‹0.³*(& \’] ]Žú}ì v äûN©¬B? ±¶þkö4íYãßÙŽÒiÌhÇ$ÄaÂÀÁPÂ"ÄÅÇßͤÕ4á•ïÈþ0L*ê2Î9 >™@åAëA´@X>œ:¿4,-ó#À ²õ ìLåÀß3ܶڹÚçÛxÞêáÏåÆéní~ð©òÎóÊó§òtðoíÃéâåâ²Þ0ÜÛCÛ÷ܹà]æ×íûötÿ %ï-i5;Ž>Ñ@áA½AK@¤=#9ì1×(’j ÿüÙí“ßžÔûÌ,DZãÁZÂIÄ¥ÇåÌ"Ó­Úaä>îp÷°ÿš ýU2Ì_@É T :ÑQïÄÊ ôÉÝ ^&È*.c0¢1„1ö/Õ,ä'ñM* ïûî(à£Ô ÌPÅÁI¾«¼a¼Z½§¿äÈþÐ5Ûfé!ø“>¡ ÷)ð/I47ï7|7}5O2!.A)Ù"T‹ ÷–ÊþCþØþ1%GB¼cö?#¦þÊøÄñÝélákÙ+ÓôÍ™ÉÈÆLÅÅ?ÆòÈÙÍgÔÒÝõêAù2Cx%—/È7=`@rB@CºBú@ >…9ƒ2*k" »÷•ìüâjÛ¥ÖÔ÷Ò4Ó•Ô×®ÚXß~ä~éíí•ñ/ôªõôõ'õfóìð îëdè^æUå™å_çÑêóïÀö ÿ‡ûáù'…/6Ô:Ô=ƒ?@g?=ý94,Ø 3ÔYóJä?×lÎfÇ Ã¢Àp¿¿¹ÀÃÇ÷Ì'ÔÝxèóôý:`á©ÀbÆF<ûs ¼  m ¬JœU!<%O(S*+­*½(ï$‘ß SÙóãæSÚÑIÉÆÃdÀ(¾½X½Ü¾£ÁÆ/Í.Ö,ã2òY*J)£0d6Ü9°;<";ô8D5;0v*!#%‚– ²%ýðø8öäôÒôÊõ€÷žùÌû©ýéþ@ÿ|þyü'ù¡ôüîˆè‚á­Ú&ÕÙÐXÍÝÊ»ÉÊñËvÏ ÔCÜ´ç£ô’ ~d+(4ñ:?çAnCªCœBJ@к>z=ë:Ñ6à0&*M!öÿ ÕÐû1õð¨ìÂêWê"ëäìBïãñkô€öÚ÷;øv÷‡õeò:î:é¥ãàÝòØÕBÒnÐÌψжÒ}ÖÍÜDæiñßý8 ì&Œ/7ä[:D3]*·ÿ,æñäiÙ Ò·Ì ÉUÇÇÈ®ÊnÎÓ°Øãß®ç ïŽõû5ÿŠÌ‰•ÿýûZúëù¬ú©ü ÉÐ Ú¨à!û(x.*3é69ò9‹9¾7Ø39.•&p îþõï)áåÔ Ì:Å ÁP¾à¼­¼Õ½)À ÃVÉbÑÛ?è¾õÄÜŽ"”(6,.¥.×-ó+)û$ÞiK¿+ › ?  î » &馢0k%‡ ]Õû4òÓç*Ý ÔÓÍòÇÄÇÁ¡À¦ÀÞÁvÄÉOÐ}ÙãæëõWºY#Æ-Î5l;§>‰@A@°>¾;ð60)(|éÄü‘óìbæqâHàÅß±àÇâ©åéjìïòÃóbôåó:ò‹ïòëÄçDãÚÞÛˆØøÖ¦ÖÒךڒßÛæâï}ú5½‚y*›2Y9Ã=Ž@9B¦BÊA¬?N<”69.¼#¾™öèÛÒËÔÆCÄ/ÃkÃíįÇ)̹Ñ;Ø´àëé¤ò}ú&yS ­ ¨ _ ' > Óþà¶«é[ ¥ É ë&Ð+¡/›2l4í4å3K1-Õ&(&áÎõxçÛÙÐÈ¿Âd¿5½J¼°¼_¾EÁ¯Å²ÌƒÕÃáðUþø †Ž#ó*É/3±4Ì4}3ð0q-)‰#³%+ %gô®s^ p ú « 5 r -uRýéõ{ípäKÛ'ÔLÎ=ÉêÅÕÃ&ÃäÅEÉKÏñÖ–â³ð­ÿð÷‹*e3?:x>AuB‰B\A?b;˜5Ò-m$Ø) ÿ÷óHêAâ,ܺØïÖªÖÇ×üÙ4Ý{áüåUê4îDñZóRô ôßò¤ð¼íaêûæÛãkáýßçß_áäšéiðÌø‹d ÔY$-L4þ9®=è?Aè@‰?øÃàÈAÑ–Ûêûø¼½‚"Œ+Ê1j6û8ð9‘9ø7Æ4h0F+è$ßç} ÆâýPûúú û°üÀþÆ…ŸÁÂpÒüÙ÷¼ñ©êãJÛÕ4Ð ÌðÈ]ÇÇ$ÈËÅÏÖÇ߃ìuú ðæ%ß/ý7H=’@¯B„CCMAY>ä9Û2D*Zž 6ö{êWà¾Ø Ô:ÑòÏ ÐlÑÚÓ7×»Û[áçRìÚðiôÒöøø"÷NõêòJðÉí¼ëêqêÁë‘îóù‹K û;é&J.“4v9°ê>Y>„<Þ8É2æ*tö´Fò6ãLÖÍ Æ[Âß¿›¾£¾Ö¿9ÂÆ÷ËbÓÜjèô5ÿ% À¬Ë!‘"v"ð ezÙ«‡ ÷ ˜ T ˜¢Úå A$V&[''9%l!bñ ÿ'ó½æ˜Ú–ÑýÉwÄÁƾ¼½í½l¿#¡ÆÖÍéÖä=ó“­¶*52 8k;$=ƒ=Â<¢::7ø1ã+|$ûœã,ËúÏõ`òoðÞï‚ðò'ô}öµøwúsûrûFúÜ÷?ôïåéªã-ÝÁ×zÓ(ÐÈ͘ÌÒ̇ÎÚÑÉÖÒÞÆéDö¾ÞóŒ+)4â: ?ÔAdC£CœBK@Ñ<67×.¸$¡#ôù‘ìˆà3×SÑ$͛ʱÉJÊHÌhÏrÓjØÄÞÙå“ì‹ò‡÷QûÔýÿ ÿ8þ‰üyúEøjöõÅô–õÃ÷hûmØeÈ­Î'.i3Ï7d:Õ;ö;±:83I,ê"’øØè™Ú~ÐRÈÃտ̽½£½s¿^ÂûÆÎVÖêáíî¨û”R}Ô"o'!* +º*8)x&Ö")càúê ð  b · øÓ%çÚ½3=œ[ ‰˜÷´ìlá0× ÏõÈ\Ä…ÁÛ¿Z¿À›ő˹ÓéÞíýq gb(!1$8y<Ô>ë?×?‹>2< 82+" i ½ùdò—ìˆè#æRååå“çêíìÝï‡òô¾õÞõÔô¥ò]ï6ëcæEá5ÜZØfÕ¡ÓôÒ‰ÓˆÕwÙïߨèrógÿ5 €,&u/N7¦<ø?*B'CÖB?Ag>ð9¾2Ã)½Î Ëþ+ð—âo×(ФÊÇnÅÅ#ÆQÈCÌ-ÑÙÖ?ÞËææîGö•üŽ8jS × éãMÿeþƒþËÿZBf ›š õ&j,Ö0i4Ú6á7|7i5 1E,{$å¥ wýÌî9à`ÔžËìÄÒÀ¾¤¼u¼š½ù¿wÃ8ÉlÑ`Ûøèêö]û.W%A+ê.1¬1î0ô.,(#ù¼; È ƒx¬… æ [§W#ÁóŸ ³F‚úŸñóçôÝŒÕÏ[ÉmÅñÂÓÁÖÁÃÒÅ­ÊÂÑÛŸèƒ÷Ú. $Í.ã6O'&ä#p 0žäP xƒTòÿNÿPÿÞÿÁßýì€ ×ùzþfûÝ÷ô*ðbìëè÷å¸ãNâáávâäÇæ^êÐîáólù7ÿ÷“ ºJ ëÇ oH@s=. ü:×üöù÷àõÃô7ô4ôªôxõ’öÏ÷ùgú’û‘üZýáý3þCþ*þåý‹ý)ýÉü‚üSüQütüÊüDýîý«þ‡ÿ[5©@žéöä¡HÖo¥EæŠ>ÿÿkismet-2013-03-R1b/wav/README0000664000175000017500000000017512124602454015133 0ustar dragorndragornJunk, new, traffic - Stolen from the Enlightenment ShinyMetal theme Alert - Stolen from Windows version of the game 'Wetrix' kismet-2013-03-R1b/wav/gpslost.wav0000664000175000017500000025427212124602454016476 0ustar dragorndragornRIFF²XWAVEfmt D¬ˆXdataŽXýÿ>ŠæE¥jÜC¦Þýá§8¯ý7[…ÿ¯þéýHýÈütüQüSüüÌü&ýýäý)þFþ/þæýVý“ü’ûeú"ùÍ÷“öxõ©ô5ô8ôÁôâõœ÷ôùÛü6þ - >qCFp ÇêG¾Ž û5ÿlùãóÌîbêÅæäwâßáPâ·ãøåêècì)ðôÜ÷gûzþùÖ…çÿá¾áÿLÿQÿòÿTz Rä›5j ê#&?'E'&g#´„õ>Åþ´ô’ê´àNØ_Ò·ÍOÊ=È¿ÇwÈÅÊÎhÓýÙ8ã¡íVøßê ã&$(a*3+ß*v)Æ&8#i]U¹½ ŸƒtlW÷! q °igKä œ­aûÖòzé¨ß×tЮÊHÆtÃÂáÁÓÂZÅÀÉŽÐEÙ0æáô-_"G- 5‰;?#AûAAõ?2=Ð82F*­p€_ühòîé<ãcÞ‘Û¨ÚۻܠßJã8çë•îNñ(óÝótóðñkï(ìgè}äÑà¾Ý½ÛÛ»Û1Þâïèñ¨ú‡Esˆ(®0Ã7‰@AÕB(C*B÷?¦×?ë?Ó>{<"8#1`(hq ýŸíæÞ»Ó‘˘ŠÂÀ\¿Ü¿‚Á_ÄóÈ Ï2×iá·ì”÷ŽW ž<7¹Üæ$Ñø¸ a  ï ë úàb*Ô"|&6)¹*+*t'Ñ"~Q•§ûïîèáVÖÎøÆbÂp¿¥½½Î½Ó¿ ÃOÈЖÚÚèø•ç"K,ÿ28±:÷;Ó;e:Ï7i3.Î'¬ÊcÙmgûÄ÷—õÂôõföHøwú‹ü5þ$ÿÿÖýPû‡÷ŽòŽìÞåÀÞkØtÓeÏKÌIʰɜÊ#ÍSÑ6ׄà•ìñù"¦²$Þ.07Ôí>Y>®HA CƒC¯B”@D=8Û/ê%ì túƒìÆßÖÂÏË#ÈÇ]ÇðÈ Ì6ÐÕNÛãªê½ñÖ÷ÕüoÁÃ…ɺþ·üûúúPûâýÉ ƒ ßçã$I+g0Å4ø7“9í9ÿ8g6Ê1Ž+"·þøê•ÛCÑßÈ>Ã׿™½§¼½¾pÁ²ÅnÌÕÔà¢íÿúµDXB%N*-~.s.5-ê*'#®Qd7 î N ¨ :¨Áý «¹Üøî˜ã{Ù×ÑPËHÆüÂ1Á‚ÀÿÀ²ÂÆÍËŸÓ[ÞÌìü‡ ª( 1k8õ<‹?æ@Aæ?°=ü9N4-Y$Õb ‹Ñøað£é•ädáåßþßjáÜãùædê¹í¨ðÚò$ôPô[óEñ2îVêüå|á2ÝÿÙÃ×®ÖìÖ½Ø(ÜFâDêøóÿ% Ük$Ò-˜5c;þ>_A†BvBAx>@:d3‹*øí²ÿ®ð˜âóÖFÏLÉÅ¡Ã$ÃÖÃéÅ?ÉJÎ'ÔMÛläíçõRýu/n : ¦ þ m ` s®òk! )%´‡#)l-ô0{3Ë4µ4 3Í/ñ*Ž#‡÷ UþðÁáƒÕ²Ì¯ÅFÁ^¾±¼I¼6½d¿½ÂÈÐßÙtçÐõà''×&-L1ç3ê4p4˜2£/Î+ì&Ê ©_ ç«·ÞÎ< & b ¥ ¯ S w'}ú¥òêéµà9عÑ+Ì­ÇðÄgÃ1ÃAÄØÆzË#ÒûÚè—ö¾¼#:.‘6Q<©?ÍA¤B:BŽ@Á=\9—2|*‚¼6{úåï׿˜ß•ÚÔצÖ÷Ö‰ØÛÙÞEãÂçõëˆï=òâócôÃóòïiìé©åÆâ²àÅßHàrâ_æì’óŒüÈå~+( 0ô6º;³>€@A‰@§>k;Ñ5Á-_#²_åõèæwÙVÐÉ|ÄÙÁ¨À¡ÀÈÁÄòÇÔÍÔ.ÝÐç7òÓû]‡ &m,¦¨è(· ó @ ž % ÇCoÚý$)ï+Ü- .".1,–(Ž"Üľõ@èÛdÑTÉ¢Ã)ÀÓ½¯¼Þ¼R¾ Á:Å ÌæÔ)áôïïþo “&<.Ó3Ä7†9õ99ì6(3y.ú(á!¦ÝÎ Ê ¬ü©úîùWú û}ý•ÿŠÐ†4ÿûõï°çáß³ØÓoάÊÈÇUÇ É¸ÌÒkÙœäæñ,þºY*H3X:º>”A0CC‚BG@ç<˜7“/ &ó1 äýgñDæÎÜ{Ö¹Ò‡ÐÊÏqÐ?ÒÕñØßݦã:é8îhò„õx÷;øØ÷ökôâñDïâì#ëVêÃê¦ìð+õÖûÐ öJ!+*Ù0Ø6ç:{=¼>Ú>Ì=L;ä6Þ/'æ ¥û>ì}ݲÒvʤÄ8Á5¿s¾ô¾ÀdÃðÇÀ΄Ö'á í™ø>¿ ´óTë!·" " *±‰‹[ %  ! EZI{X"4%ã&p'‰&!$TúÚ‡úYîÖážÖ~ÎÇßÂù¿4¾ž½Z¾NÀ„ÃûÈ/ÑnÛîé<ùz8¤$Ò-¿49`ý@¸BBCoBe@=Î7‘/}%@3BùñêØÝaÔàÍëÈCÆÅNÅÇÆ™ÉôÍ+ÓkÙláÝéÅñÉø¦þ$=øb¼CF%2ÖþEþÈþ„“úˆ OÞ"=)$.O2|5|7ð7ÿ6L4î/ø)  ?“ øgé3ÛÑ¡ÈÃ¥¿Z½a¼¬¼G¾ÁOŠ̤Ô'àîðû( Nñã'×,ô/†1Ÿ1e0.È*^&Ü É óË ÄíTÎ<V Ä D]Ì4Sü –´ÿn÷>îbäªÚ'ÓßÌ«ÇEÄ\¤Á ³Ã+ÇüÌÔ•ß×íýf –Ô(î1#9¡=O@ºAäAÍ@’>;j5ð-%ù {ôöÛí\æ¹àøÜAÛÛ/Ü´ÞâàåÆélíwð¤òÍóÉó¯òzðpíÅéÏåéáyÞéÛ´Ú¼Ú-ÜÄßJå¡ì±õ ¾÷#'-Ä4˜:Z>´@êAæA˜@ >Ð9ç2*K0Éþ•ï2á§ÕÝÍÅÇ$ÄMÂÃÁ^Â(ÄdÇlÌÒÞÙ\ã1ímöµþ²= E©ªOùæu  ì}ù‘Ya }•[~ *&±*.‰0ì1ò1†0-ã(L!Ë· ý­ï­áŸÕãÌßÅiÁz¾À¼K¼)½K¿£ÂâÇþÏÜÙ¯çhöÞ¤#ê($/©3†6µ7Z75u2a.¦)l#í¸,—) Cÿ¹þ=ÿ–„©­3í‘ñåxÿ¦ù£ò»ê9âÚÓ:ÎÁÉÂÆ+ÅÐÄÓÅ@ÈüÌdÓ8Ü;éz÷m‹($”.ÿ6©<@DB8CÓB5Ag>:g3+ò©.ùêí0äJÜ]׌ÔRÓoÓ¸Ô×¥Ú8ßMäDé°íTñúówõÎõõEóÉðØíÑê èíåÆäéäŽæÝéåîšõÓýM¼¸'ã.‘5:»=Š?=@´?ø=¦:5"-¤"½7õ æ•ØfÏ ÈsÃäÀ“¿z¿—ÀËÂÆJÌdÓúÛ<çVòÃüvý7õw áÕR ‹ Ï / ¼ gf- !F%{(–*~+2+ˆ)à%Ú` çhõdè{ÛïÑÿÉ2ÄŸÀ:¾ ½"½„¾(ÁMÅÌñÔRáNðŠÿec(Î/¶5y9q;ù;(;9—5¨0ÿ*ë#hz ˆãý ùÇöfõ>õ,öÚ÷õù'üþ[ÿÆÿÿý×ùVõ³ï5é$âÛoÕúÐZͳÊcÉ‚É?ˣΡÓíÚíåÉò¯;ÅR*:3U:Æ>±AfCÇCâB±@Z=80y&ç ýùï>ä‚Ú>Ô&Ы͸Ì<Í ÏèÑÕÚ«à çöìò8ö"ùØúPû¶ú8ù"÷¹ômò„ðfïXï›ðUó¡÷ký–ð *Ô”(//ö4V9+<=¼=È<>:Ê5/=&8‰ :ûÚëÝ?ÒÝÉÄ™Ày¾ž½ ¾±¿zÂÞÆ™ÍÕTàÌìùk¬h^k#&'°&%P"‡Z2jO!   D txÿÄUf ‚"h#¿"^ #=×2ú¢î¢âž×ŒÏpȬûÀç¾?¾Ö¾µÀÓÃGÉaÑšÛ-ê‘ù œ%á.6Ò:=Á>Æ>«=K;{7 1ü*‹"05óÛüöÞðMíEëÁêuë(íïò«ôËö1ø£øñ÷ ööòÈî¿éä<ÞÙÕ"Ò*ÐYÏâÏéÑsÕXÛtä}ïìûI §$‹.È6…<@rBšCwCÿAM?0;ƒ4®+Å2Ñó`æ°ÚìÒaÍ~ɆÇÇýÇbÊ Î˜ÒØ ßáæ9îÒôXúžþ‰{Ä?Jÿ!ý3ûÔùNùíùÓûÿÀ´ À é S( .é2Ü689E: :p8ê4t/@("¦òã$ÖÍäÅiÁ†¾à¼‹¼x½«¿úÂ1ÈÐsÙPæÛóù5 S!Ì'±+Î-t.Ô-,I)E%D Ô©o Î f "  Ç < â^%çM5iõ ãlýÊó]é•ÞzÕÎRÈDÄÄÁsÀNÀWÁ©ÃñÇêÎ׊ä…óyN!„,Ð4Ó:`>m@3A¼@?_<Ó71|)!†PýýÒô2í<çãÁààÞàÛâ¯åÿèqì”ï6òîó«ô:ô£òöï_ìè‰ãùÞÛNØ~ÖÖçÖyÙûÝåñízø+¿§=) 1À8o=m@EBèB?BQ@%=ú7Ù/Ì%~1ìø7êŸÜ7ÓPÌQÇÄ>ÃKáÄ8ÇrËèÐ*×nߦè{ñjù<±° 3 E " í  ÉŠ aïs ±÷`&+…/¯2Á4z5´4P2N.‰(eŠO<øÆé¦ÛfÑ÷È8æ¿?½¼O¼Ì½ÀšÄ6ËçÓeß³í üØ ¢ó!*%/¡2…4Ó4¯3N1á-Á)=$‰íà° Ÿ¿3Õ’"D˜ Ë ~ Y q ×Öþv÷ïèåxÜïÔêΞÉƲÃÚÂÃÃÄûÇ®Í ÕÜßéíëüM †î(*29>ä@BÅBÍAœ?T<ó6J/>&? ùµõ¼ëxãÝ=Ù9׿ֱ×ÉÙâÜá¢åêõí'ñTómôSôóíðöíŒêç²ã á\ßÿÞ7à&ãïçîÁöj: ¿"à+U3u9u=í?>A`A8@Õ=±9ï2;*‘sæþxïºàÕí̸ÆÃÁaÀàÀƒÂƒÅ6ÊÐö×¹áZìrö±ÿ¡#ü,¹Ô±©5ƒ X ëŠI B dŠƒö’"5'â*c-á.3/.“+ 'Æàm ¹ýGð‘â^Ö«ÍwÆÍÁȾç¼N¼ ½¿GÂSÇQÏ"Ù çöOh Z*ê0Ñ5Ì8õ9Õ9g8~5C17,&A0¥uþ¹ûXú9úûÍüáþç.‡´˜#þHù@ó1ì}ätÜàÕÁÐOÌâÈ Ç‚ÆNǰÉ%Î#ÔÜÜiéS÷³#I.Ü6·O?ú>j=?:É4"-Ø"q‡õ&ætØÏ€ÇÊÂÀƒ¾C¾C¿nÁÛÄOÊ¡ÑQÚãåÅñýU?Šþž b"",!²uÇÄP  ¯ YÚûW£ G$²&((‘&q#¼Å óöéÙÜ$Ó9Ë+ÅFÁ˾k½\½‘¾ ÁÅ‘ËbÔsà“ïÿTÜó(ù0N7; =¼=3=h;E8O3U-8&ÿy… áûŸöíò½ðð€ðúñô~ö×øÃúúû5üHûùõùð_ë åiÞˆØêÓMЗÍÌæËBÍ8ÐÅÔÄÛ`æ¹ò5t͘)•2ð9•>®A‹C"D`CUA>9K1»'Eœ 'ýhïæâÁØ?Ò«ÍÉʃÉÖɔˌÎuÒ4×LÝ}ä[ëˆñ¼öÉú…ýýþ4ÿ^þ´üú4øöˆôæóaôDö›ùnþ§ …„7&ú,¢2s7d:4<¡<Æ;k95µ.<&ž. üšì”ÝsÒÅÉ·ÃÀͽ½¼½†¾<ÁSÅÆËûÓ‘Þ°ë³øñ¾Š!Æ&Û)+ù*¾))'Ã#:“k!á Ê ð & cEòýO’Ñb+- —»úÏïZäcÙ&Ñ!ÊïĬÁ¬¿Õ¾<¿ßÀÍÃøÈÚÐØÚ2éµøeÈÈ%o/7ò;®>"@O@P?/=Š9ú3-µ$ÔòÁ ûØó¦í$édæ@åå%ç”éˆì›ïzòÂô1ö˜öÈõËó§ð„ì°çaâÝÆØrÕQÓ?ÒoÒÔ<×ÀÜKå–ïfû7³6#i-¶5Õ;¡?2BCC]BÐ?< 5Î,8!2äðóÐå¤ÙˆÑ„ËlÇ_źÄoÅYÇÌÊÏÕîÛ˜äûì³ô\û¸°8Q:B Îûþ¾ý‰ýqþ°MA Wbõs%d+.0(47s8|8"7Ñ3Ú.(gT:óMäîÖ›ÍÆ[ÁB¾`¼Ô»š¼¬¾ëÁ߯‡ÎÉ×ÀäÛòµ» ˆ #Q*v.12œ1ç/-w)‡$z\Ãñ 3  Q9. r !­½ú ¼Ö[ DÁý÷ôDëá¯×šÐqÊßÅîÂoÁÁÛÁ÷ÃõÇ›ÎðÖãbòížÎ z,#5\;?[AaBB™@ö=Õ9q3“+p!ÜýNó¥ê¿ãÊÞÐÛÓÚ6ÛãÜÚ߈ã‰çë ïáñ½óxôôeò½ïCì@èäà®Ü•Ú§Ù ÚúÛ'à\æhî"ø(.²k'07Ÿ<Ã?ÑA°B-ä'PVùUëÝkÒÑÉšÃÙ¿8½Ù»Ï»½Ÿ¿WÃqÉ4Ò5Ýìû’ <k#°+[1[5©7*8\75ƒ1-Á'ñ V/Õ ŠðÿŸþ˜þÿMƒØíb ë A 4­¶þUøÓðhè’ß×sÑ'ÌèÇmÅÄÄŠÅtÈÑÍÊÔ ß·ì‹ûà :(½1{9T>yAZCçC!CAÜ=ù8m1|( Œ`&õ.êäàýÙ´Õ‹ÓÆÒ`ÓÕù×ÚÛ÷à8æ-ë~ïæò0õJö%öêô·òØïìe鋿ä„ãþã æåé€ïÓö«ÿµ ¥ ù)b1õ7Z<?@í@@ù=8:í3r+q@e“ðGáøÔXÌáÅùÁǿ;¿šÀ0ÃvÇßÍTÕߦêÊõ5 صÒÈ÷ú(Ùyhï i ö ¹ » ×î¯Ïä"ë& *Ï+„,è+å)À% ú6 )ÿò¼ä=Ø/σÇtÂ(¿½¼Š¼R¾YÁƤÍ1×øäoôçåË :+e2Ü7ã:n<„ƒ>H=q:z5#.~$gP÷¤ç;ÙAÏFÇCÂ)¿P½Æ¼’½‘¿¸ÂŸÇÏ×_ã$ð‚üÞüm÷ =%T'Þ'ù&ç$›!eô¡ÒÐ Ö x  ³$ ã" $¨$è#.!ár l0øì¡ßÕÍsÆ ÂX¿¶½P½9¾lÀñÃõÉ ÒøÝRí7ý C')¾18£<Ê>·?d?ò=3;Ö6‰0|) oK  ú¥óÑî­ë.ê+êbë‹íBð0óæõøkù°ù±øpöéòTîÝèØâ¤ÜרӫоÎÎ×Î.Ñ%Õ|Û\åñ,þ c©'619/>™AÍCµDEDyBk?Þ:’34*Í ¤þ÷ïqâx×eÐ ËÁÇVÆRÆÇYÊtÎmÓmÙáéð÷tühú!Øê“þ#üú“øøÞøûªþ´) ² É"*Ë/À4‚8œ:ˆ; ;,9Z5w/ž'­~ UþÈîlß[ÓDʦù¿½’»‹»Ê¼[¿ ÃËÈAÑ]Ûé÷jÈ›~$(*o-%/i/P.,à(z$ã/ßK½ V <Oš Á ¤Òý¶¢_°R.H ©¬üròç:ܘÓg̙ƸÂqÀA¿H¿—À&ÃÂÇ1Ï—Øjæöüð$T/¡7Ý<ö?ÌAMBˆA?}<Š7D0õ'ÇÉOåúÉñWê¾äá/ß ß`àââ'æßé‹íðð”óTõäõ:õOó=ð6ìˆçâ–ݧپÖ!Õ¿ÔªÕaØ!ݵä;îQù­ÔA s+ù3»:?ùA¼C&DFCA†=ú7R/„$IY™õæNÙxЫÉWÅòÂÂtÂñÃøÆ›ËŠÑlØ^áöêïóùû¬ù­ Ð xÔ - Ó (‘g ½¸ËÏ ëÓ+!¾'â,1]4l676}3 /)ZÜøDö0çÙïÎÀÆwÁñ½¥»®º»å¼ú¿VÄm˲Ô9á7ðÿG FX%Š,r1©4,66‚4µ1á-N)Q#)ì¦  ôª¸àñ‰Q ß Ù×¡ë ž ´>ÿi÷sîÈä ÛvÓ'ÍÎÇVÄW‹ÁòÁˆÃÇóÌÔÔDàïÐþÛ«’+à4È;Ý? B DDÖBR@²<ð6¼.þ$è¡ þƒò~èGàqÚ׃ÕvÕ¶ÖJÙÙÜ¢ážæfëšïèòõö¡õôiñîêæjâuß’Ý!Ý]Þ~á‹æˆí4ömÌ ó?$‰-\5@;?}AÉBÌBrAÒ>‹:}34*»Æ ‚ühì0ÝRÒÊ|ÄFÁ‚¿¿Ç¿²ÁÜÄÜÉÀЭØ<ãcîòøgŒ ü®…£6á¸g\ åaôÞ † „y’#o(.,æ.Š0ç0À/-Œ(!ªŠ (ýúîà…ÔqËrÄÀþ¼%»®º’»Ú½eÁµÆÏ–Ùgè/ø½‡ö#ÿ,›3K8Â:½;K;“9r6½1+,o%áHf üù•øíøQú…üÿ¸”"d9 ÿ}úô‡ì;ä·ÛÝÔ^Ï›Ê4Ç_ÅÄÄžÅâÇyÌâÒÅÛéº÷C & 0#9>&B…D~EE[CY@1!@Aš@í>×;]65.Œ#R³ó˜ãÙÕnÌ3ÅÜÀ¾›¼€¼°½$À§ÃgÉYѹÚ3çÕó³ÿh çC ™#Ç$t$¬"˜¶t=ri l   ) þ ýý¡Ÿw!|%E(ì)#*Ü(¼%= >bèMöñè•Û›Ñ?ÉMÿ»»Î¼x¿^ÃïÉDÓÔßéï^‘è¬+ä3æ9[= ?‰?Í>àÇ=º;Ô7%1¤(®K ü™ë¦ÛWÐ[Ç©Áè½t»jºÅº‚¼ƒ¿žÃHÊ-ÓeÞ‚ìgúrD_4%*¢,¢-C-+Í(Ä$sÎl®ô j =wõ )ëòÒ 5!Ø?þŠüäðŸääØ"Ð{ÈDÃí¿®½§¼ö¼ž¾¦ÁzÆuγغç`ø7 ºA(2­9A> AzB™B_A?[;©5.%Kƒ „¼ø{ðøémåÃâûáÍâþä$èæëÅïdóZöSøùwønöó‚îéã÷ÜØ?ÔšÑÐîÏCÑ6ÔGÙ}áZìÙø›´#‹.’7›=¢A‡D F6FáD7B/>=8à.#ìpPò(ãœÖÎ$È|ÄŸÂ%ÂçÂóÄeÈÇÍÔ‰Ûåjîæö1þø*« ‘  H ´¯™õýü+û±û³ýFeá t»%¹+*1Ê5û8®: ;:f7V2+c!n$ôêãµÕ£ËçÃ7¿Ã»´¹ ¹Û¹¼’¿bÄÌçÕ‹ãéòçÜ' -ø1§4†5Ø4ª2T/+“%¸–Š =^ô eÔý  ñâòÀ? A÷÷…íaâë×Ð É#ÄÁ8¿¾3¿,Á¯ÄÑÊÓÀßË6"a.Ô7Ê=®A8D_EEuC@<'6{-á"/ÈDûð—æ(ß@Ú¸×çÖ½×åÙJÝ÷áçýëzðô‹ö©÷[÷«õ¹òÀî êåà¾ÛÜØ'×ÝÖJØxÛlážéËóŽÿ~ 2'É0é8=>åAbD‰EOEžC@<¡4–*8W Mú•é[ÚðÏÜÇâ À‡¾\¾¿ÊÁ„Å?ËžÒSÛžæ¼ñðûÖ# ž7èìoØ~Ú RS6H¼²' êE!Ñ'ç,14å5 6±4t1m,î$Q¾ ÞüJí•ݳÑÈÔÁv½\ºœ¸R¸‡¹'¼$À²Å”ÎËÙ˜é)úQ ‚Œ&/k5m9q;ñ;õ:·8Î4”/°)ç!«J . þ§ûKúxúñûvþý&Ê X F 9fòüýôàëâ¡ØgÑ"ËPÆ/ßÁ1ÁÂ[ĹÈ÷ÏMÙbçg÷5(¡(d3¶;Ç@vDÃF•GëFÍD\AÁB9¡0v%0²òßà[Ó‚ÉÞÂØ¾,¼ðº*»¾¼¢¿ÃèÉjÒŽÜËé˜ölá ”FÙ F#´#U"€˜ Vß % p0Ûþ të c!Ï&ý*Ê-s/±/X.L+ð%:#÷&è®ÙÏXÆ·À›¼Ë¹W¸a¸ò¹õ¼_ÁËÇíÑ4߇ð& #+.{6ß;Í>K@h@K?=)9R3T,ì#.ႃý÷òÈïáî ï¸ñÖô‚øNüÆÿlùŽ_ÿwú ôoììãDÛTÔºÎéÉ´ÆøÄÄ¿Å~ÈÌÍôÔÑßZîPþúÒL-³7w>0C¢FHIüGcEnA3<À3á(’øÙøÈéPÜnÓ;ÍäÈÛÆiÆdÇéÉùÍùÒÙ×àé§ð'÷>üÀÿ‚¨J¹ý4ú:ö3ò¤îõë–êÒêíìòðñö¸þ©ª(©0Ñ7®<µ?§APBžA~?æ;w50,7ü9êb٨ͷÄF¿a»ì¸ü·—¸›ºü½|Â-ÉÁÒ±Þ¢í8üÅ Þ C'+—-.ô,Ÿ*Á&!^;šï Ž­pÌ¢ µ ¨v`"Û%û'Œ(o'b$ŠP µòŸä`ף͗ÅYÀ”¼ºÛ¸0¹»h¾(ÃýÊÖÕ¢åÀ÷ dz*á4?<}@KCªD’DCU@€<\6.I$‡ ½ÿÄõ´í¤çÉãâOâNä›çÙë€ðõ/ùNü+þ{þ&ý!ú„õ’ï‘è÷à½ÙÔ¡Ï8ÌÊ›ÉÛÊÎÓ°Ú‘æ·ô4‰Ë$ 0&:;@ÀDòG©IÍIeHoEAA;Ø1¦%r”%ñÒàGԸ˲ÅO½À„À˜ÁàÃáÇêÍØÔ~Ýãç¬ñUúzêj Ò  P+ÿûš÷#õô™ô÷Yû„O Š~&..Ö4÷9F=?›?Õ>«U8Ý.ˆ#‹¥øÐìã¶Û’×¢Õ€ÕöÖÚ†ÞRä`ê;ð[õ]ùíûÎüìûQùõ­ïFé‚â×ÛÑÖJÓÑAÐÑÌÓ·ØáyìÉù’1O'X2D;ò@UEeHÿIüIaH%Ex@ï9w/d!‚ûÞè>ØÍëÄ(À½’»†»ó¼©¿|ÃÉÕÑlÛâçðóæþAÁ LVdÌìB F‡ÿ³üQûÃûþHFÈk«!Ñ)õ/^559j;/“>=; 7ü0(*P!.Ì ”ÿAú÷Äöá÷¡ú–þW[+ (èùÿ¿ U û^ðŸä Ù8ÐcÈ׿E½>¼´¼¤¾ÂÞÇ_ÑSÞbð{ðÛ(I5 >ÔC8HýJL~K?IvEY@•92/"ˆñUãØßÑÍ7ËÕÊ5Ì%ÏKÓ»Øéßéçgïïõûyþÿÿ“ÿVýtùSô^îèâçÜ–ÙÛ×ò×Ú´ÞVæVðgü É>'û1Ï:‡@áDðG„IyIÅGjD?s8-B +õnáÒòÆ%À[»%¸Œ¶Ÿ¶J¸i»Õ¿ªÅ«Î‡Ù èÎö^M&!ù%Û'®'µ%î!vBר ¼ÿþèþÚ# i!·(.{2…5ü66 4œ/î(ÞvWÿî]ÜSÏîÄP¾¹Hµ³²Ó³Õ¶u»‰ÁÊa×íéÞýmÔ#T0š9?‹BsDÀD’CAH=°7m/ø%¨o hù¹ñ­ìóé”é8ë¬î^óàøþÛJT × ãÁšü²ónédÞìÔuÍ ÇäÂeÀ5¿e¿Á€ÄàÊ@Ô?â>ôq,,ƒ8x@uFKîMOmNþKåGTBL;&0v!;[û„éîÙÚÏYÈ"įÁ ÂÅKɄφÖàß%ê•ó±ûöEc^Kwý•÷`ñ‰ëæãkáâ'åÌêäò;ýW ÔÌ$t/•8¬>C9FôGHˆFECo>ô6=+/× ñrÜäÍ*ʼ_·Ò³ ²²å³]·M¼v¬Ëá×¹èús $%”,91¹3)4®2/(+%Î qhFþ;ýUþytå J£#9)ù,7/Ë/p.+Ñ$td gþýíåÜèÏtŪ¾R¹Oµß²+²A³.¶ÐºÁ(ÊÊ×¼ë7 )o6Í>mD\H›JKÀIÖFŒB=Ò4(*ã— vþò½çà:ÛYÙ¯ÙðÛˆà”ætí…ô*ûÂå&áaÒùŠñýçÈÝ9ÕÎàÈJÅRÃþÂ>Ä’ÇÃÍZÖ1äfõ‹,9&AyGcL¥OQžP:NJ,D÷<_1!< ÷ëâÓ#ÈŠÁn½úº<º»½ÁTÆ:Î|×Åã{ð ü׊ Ғ̼< Ôýµö:ñCíFë˜ëpîÔó¨û•= ÷)ÿ2:z?ðBEºE·DB =G6á*Ç6Îï¨Ú¨Ë*Áý¹?´:°®ã­²¯O³«¸g¿8ȪÕuè¥üÝk!§-(6j;>à>;>.Ÿüì°Þ=ÕªÏUÌKËPÌBϳÓÞÙUâë7ôÓû»ž)¾0ýÅõí¯ã¡ÚÛÓÌÎË7ÉhÉÓ˘Ðá×äÁóR*7ê?§FLàOÚQàQÜOìKF»>£3#— wõ ß»ÎTüs·#´¼²2³yµS¹‘¾'ÅEÏœÛãënûV 6U$ô&('%— pZ Œ°ûWöýòòžóÕ÷„þX虹(1Z8!=ö?wAbAª?1³®®«Ýª ¬j¯–´t»±ÃÑÄãŠúºH%ï2„<èA‹EbGiG½EŒB>¸7C.?#>4ßü©óí=é?èééæíÄó÷úƘ °b!p³„´©ùàë ÝUÑpÇØÀñ»]¸Q¶¶™· »QÀ)ÈÕ¢èbÿ¾·+0:MC JFPT¶UMUÉR[N.H“@‘6“'¼~ýŒémØŸÍ ÆùÁÀá¿CÁÄÉeÐèØ,äšïæùTŸG L š yF‡ùØðêç€ßöØØÔàÒðÒ6ÕoÚÕãuðˆÿeL"Z0|;¸B­H8MPQ PMHþéý’ýLýýÓü¦ü‹ü{ü~üü³üæü.ý…ýîýdþéþyÿ ªNñ,·9¦Dp€vQ·@¾vÁ>…ÿÂþ þYý¹ü%ü¥û8ûáú úuúcúcú‚ú¬úôúGû¶û*üºüLýóýœþTÿ¿€2ó–>ÏN¾KmlQ¶<¤ð$CQWUÿXþKýZüiû–úÓù3ù©øLøøñ÷÷÷#øuøßømùúÈú”ûlüLý2þÿùÿË›]°>¶aŽª«”d$À[Í?–å%bžÿÒþ þ@ý‹üÛûAû¼úMúüùÉùµùÃùóùAú³úAûëû®üƒýhþZÿE:/ðªbígÀóÝ—8»0‰ÝU‰¸öÿ*ÿgþ­ýýü[üËûHûßú‚úEúúúú)ú_ú²úûšû/üØü“ýYþ-ÿ׳…P ¯@³ CWOÐdÖ4{©Öí ,ÿNþvý°üúûZûÎúaú úÐù¸ù¯ùÏùþùKú¬ú"û­ûAüìü—ýSþÿÑÿI ·hÿ” wÍ-,ìž9·sªá IÿfþýÀüü[ûÎúYúúÍù¸ùÁùïù8úŸú$û¹ûlü"ýòý»þ”ÿ[(ï¦TésÝ?y¬¶¹•jÄOÒ=¢òD‚Ñÿ ÿOþýÞü6ü˜ûûú;úûùÎùÂùÖùúPú»ú<ûÞû‹üUý$þÿäÿ¿œt9ò’ŠÚ !î­N×P°RÓ ZÿžþíýHý«ü%ü¨ûEûðú³ú‰úyúzú™úÇúûkûßûaüøüžýMþ ÿÏÿŠUÖˆ+¼<›ë'æ˜.¬ažÖù(Qÿ„þµýþüNü»û7ûÑú…úQú=ú?ú_ú˜úæúMûÃûMüâü‰ý-þçþÿHï¨FêzýuÓ(_„”„f(ÖiîT´ú>o´ÿÜþþOýœüñû_ûßúyú2úúúùú:úzúìúbûýû£ü[ýþèþ°ÿv:öªIÜV¿ Hgpe8¯RÜYÉ-‹Ý0ˆÿ×þ-þ‡ýéü[ü×ûeû û¾úŽúsútúúÂúûvû÷û†ü/ýäý¦þpÿ4ÍŽCçxóPšÂË‹MæsäJ í4tÃÿ ÿVþ²ýý‡üüûEûûÔú»ú¸úÌúóú3ûûèûXüàütýþ¼þiÿÊ€+Ùnyé8t–™†S£%“ï9}²õÿ+ÿeþ®ýùücüÑûcûÿúÁú“ú†úúµúïúFû«û'ü²üDýíýŽþBÿëÿ“9ßwˆû]­ë(  Ü–BÓWÇ*ƒÐgÿ­þøýKý§üüû*ûÎú–úrúlúƒú²úÿúcûÞûoüý¿ýwþ9ÿöÿµh"Â_âU±ù#A7'ñ³YñxðaÄ"~Ýÿ:ÿ“þøýbýÖüZüéûŒû@ûûçúÛúæú ûBû–ûúûsüýšýIþùþ²ÿi Û‰*Ã>®;bcT!Þ{ ƒèL•í0ˆÿÙþ-þ“ýýüü ü®ûcû-û ûû û-û_û¦ûühüãühýùý•þ4ÿÜÿyÄ^ô{õ^²÷4-Ú$²‰Ú*n¼ÿÿKþŸýþüküîû‚û/ûòúÎúÇúÓúÿú<û‘ûýûtüý”ý6þÚþ„ÿ#Êm˜ðH…·ÏÕĤf$¿XÔN¶sÏÿ(ÿþÜýBý´ü4üÃûkûû÷úØúáúøú-ûzûÚûTüÙüvýþÈþ|ÿ(Ü2ÎYÖ<‘ËñôÛŸZü†üZ‡ÿèþOþ¾ý5ý»üKüïû ûeû@û+û/ûFûrûµûüsüèüvýþªþNÿûÿ¢Iõ#ª}¾÷ øÆ!³-žY¯]ÿ¹þþýýü€üüÅû…ûYûBûAûTû{û¸ûüdüÑüLýÒýcþùþ”ÿ*Ãcñ…}â7€¬ÌÏš_¨4ªvÒ$ÿÕþ.þ’ýüüüü«ûbû+ûû û&ûPû‘ûêûQüÍüSýéý„þ%ÿÊÿcž2¶2›÷>s–¡ YÅaîsçV¾ŒÿìþVþ¿ý:ý·üMüêû ûgûCû8û?ûcû—ûåûFü·ü<ýÍýgþÿ²ÿZù¦7ÍK¹_›³¿¯ŠS¨7»4¢ qÜÿDÿ¬þþ—ýý«üHüùû»ûûuûqû|û¥ûÔû$üxüèü\ýæýuþ ÿªÿBá¢&™üMŠ°Â»œmÇUØI¸vÕÿ5ÿ–þÿýsýõüƒü%üØûŸû|ûlûpûŽû·ûüûLü°ü ýžý"þ´þEÿÞÿl˜uÔRo„ye2õž<ÅDµƒíÿJÿ±þþ‹ýý’ü(üÚû˜ûpû_û\û}û£ûðû=ü®üýªý2þÎþgÿš2ÄQÈBšó*\nwcC Æjˆùd×ÿAÿ®þ"þšý#ý®üVüþûÈû–û†ûû•û¼ûøûEü«üý›ý!þ¹þPÿòÿƒ"¸FÉ?¥ù;f€oH ¿_îxìcÌ8¦ÿÿþÿý|ý ý¦üOü üÙû´ûªû®ûÇûôû0ü€üßüJýÇýFþ×þgÿúÿ‹®6³)‰ã!UkveD Ádù|ögÏ6£ÿ ÿuþëýfýóüŠü6üïûÁû¡û›û£ûÅû÷û;ü”üóümýãýrþöþ’ÿ®3Å>¼ ƒÈ .KI>åšEÚjäaÍ9®ÿÿˆþÿý{ý ýžüKüþûÐû­û¡û®ûÅûýû=ü–üúüqýìý~þÿ¢ÿ*ÀRÜ[Ö7˜Ù5FA-ÿÇx²<»5¦‘ÿþþxþòýxý ý¦üZüüçûÄû¿ûÂûåûüVü¥ü ýxý÷ýzþ ÿšÿ'ºKÕVÐ5•Û9IE0Åz®2±$–yÿïþaþäýhýý üUüüíûÔûÑûÛûü.üyüÇü/ý›ýþ›þ"ÿ´ÿ7ÅRÔTÃ*€Çý1-î±eœ'¢Šsÿåþ[þÛýaýúüšüLüüæûÔûÍûáûü;ü~üÛü;ý³ý,þ²þ>ÿËÿRßhéfÐ6…Êø" Ù›Nî‰ “úÿkÿäþXþáýgýý¥ü[ü!ü÷ûãûÝûñûüGüüàüMý´ý:þ¶þEÿÏÿWálëeÓ2„ÄôøÉˆ=ÙqøxôeåÿVÿÏþKþÑý]ýýü¡ü`ü$üüñûîûü%übü¨üýühýÐýRþÑþZÿåÿgñt÷f×/¾ì é¾|.Îfìoê\ÝÿPÿÈþFþËý[ýöü£üXü'üüñûóûü/ügü²ü ýoýåýZþçþfÿ÷ÿuqÚ4~ºâþþöÒ§a±LÔXÓOÊÿKÿ¾þFþÎý^ýý©üoü2üüü üüCü{üÂüýýîýjþìþqÿþÿ{ˆuä4йëùïÔš\¤9½B¹5¯ÿ1ÿ¤þ2þ¶ýSýóü¨üfü;üüüü1üYü”üÝü3ýšýþþÿ€ÿ †oÒ,u­ØíôçÅ—T£6¿Cº3²ÿ)ÿ§þ'þ²ýJýêü ü]ü4üüüü5üaü¡üìüKý±ý$þŸþÿ£ÿ¤!¡×-k£ÁÙÒÉ¡u.ä§1®,¯ÿ-ÿ«þ2þ½ýWý÷ü­üiü<ü üüü3üaü›üëüCý¯ý"þþ#ÿ§ÿ*¯4³%–îE³ÒÝÜÁbÉbüƒ Š ÿÿ—þ'þ¹ýYýý¹ü…üTüCü0üBüQüƒü¶üýVý½ý(þ¡þÿ¢ÿ¡&ž„å:~°×áå˧l$Ífù{ÿwýÿvÿõþyþþ›ý8ýêü¦üqüQü>ü=üOünüŸüáü*ýˆýèýYþËþEÿÃÿ6µ.¢tÓbµÂư”[ÇjþŠ ‰ƒÿÿþ þ˜ý6ýàü–übü9ü'ü(ü6ü^üüÙü%ýŽýóýjþçþcÿêÿ]ßWÌ3–å.b¡®¡‹e+éš7Úcóv†ÿ ÿ“þ!þ·ýWýýºüüVü@ü8üCü`üŽüÌüýwýãýUþÔþSÿÞÿTá[ÙG®Q‚°Âƺ—i)Ùƒ¯6¿BÐÿUÿÞþlþþ ýQýýÊü—üzüfühüuü”üÂüúüHýšýýýfþÙþTÿÍÿFÂ?µ(‰é5s¤¿ÌìC÷š4ÀFÄBÂÿEÿ¿þLþÜýuý$ýÔü¡üsü^üTüaüyü¢üÜü ýtýÑý4þ£þÿŠÿÿÿoäUÁ"ËHrŒ•”{X#à1ÉVÞ^çÿeÿäþjþôýý(ýÞü‘ülü@ü<ü:üVü}üºüý^ýÀý2þ©þ%ÿ§ÿž‹úX²ù3byƒwS%êžP펯<ÐÿZÿêþxþþ¯ýZý ýÍü˜üxücüaüoüü½üÿüLý©ýþ†þþþƒÿýÿ}ø_ÅZ‰«»²£u@ú¤CÝdøuŽÿÿ¨þAþÜýŒý;ýýÌü­ü•üü–ü°üÍüý;ýýÞý?þ¥þÿ„ÿýÿiáUÅ-Œâ&fЍ¬¥…]Íp’“•ÿÿ—þ"þ¹ýWý ýÃü•ütücüiüvü üÍüý\ý·ýþƒþêþaÿÑÿ<«á<‰Î 3Tfg_CêYò–"²5ÅÿFÿÏþUþéý‚ý(ýÚüœüoüRüJüSükü ü×ü,ý…ýðýbþÝþ\ÿÝÿVÓM»'}Ò AbtxfP ï¦^ª?Ûj–ÿ0ÿÀþbþþý­ýXýýàü¸üœüüŽü¡üÁüðü3ý|ýÛý?þ±þ'ÿ§ÿŸ˜ rÒ_¦²¦ŒZ!ÐvŸ.²9ÄÿPÿÛþqþþ´ýiý&ýöüÎü·ü­ü¯üÄüáü ýEý…ýÑý)þƒþèþRÿ»ÿ$‘kÓ1‹ÖMp‰Œ~d0÷¢KÜmðnõÿqÿðþuþþšý>ýñüµü‡üoügüoüüµüõü;ýýòýRþÆþ/ÿ¨ÿ €çQ®T›Ð6?6(Û¦^·Zï‚¢ÿ,ÿºþKþàý‚ý*ýäü¨üüeü_ükü‡üºüùüLýªýþ‰þ ÿ…ÿƒ|ëLªê.NoqmU-û»pÂ[ü%Çÿ]ÿûþšþ=þíýžý`ý#ýøüÕüÁüºüÀüÔüøü'ýiý±ý þmþÚþNÿÆÿ;µ3¨Ò(\Œ¡¨šzH³Péqþz‹ÿÿ¥þ=þÝý‹ýHý ýçüÊü¼üÁüÏüêüýEý‡ýÌýþrþÐþ.ÿ•ÿøÿZ¾$†à9‡È/Re`\3 È~!¼FÐNØÿSÿÕþ[þèý„ý(ýÞü¨üxümü_ü{ü“üÍü ý]ýºýþþûþsÿäÿQ¾%‹à2u°Û ïÌœ]È~¼Lïÿÿÿ«þ>þâýƒý9ýðü¾ü”üüzü‡ü¤üØüýmýÈý8þªþ-ÿ­ÿ&¯$§ wÅ@fvxfEÙ<Þ~¯Dæÿÿÿ½þkþþÐýŽýWý-ýýôüäüèüóü ý2ýdý¡ýìý?þŸþÿsÿçÿRÊA±€Ó!W™›Žh8ì3ÊNÕPÜÿ[ÿåþoþþ¬ýdý!ýðüÒü¿ü½üÊüåü ý>ý~ý¿ýþbþ¿þÿ|ÿ×ÿ5‘ïMžö;„¹î*:2(Ú˜Rõ–#°4¼ÿAÿ¾þKþØýtýýÑüüsüeüaü|üšüÞüý|ýÙýHþ»þ3ÿ«ÿŽgÄ`£ÌôþèÀ•Z ÒŒ1Û~Ãÿ_ÿøþœþ7þåýýJý ýÚüµü£üœü¬üÉüøü;ý‡ýéýSþÇþHÿÅÿFÃH¾+‘à'Yv†}f>¾l©FÒk›ÿ:ÿØþƒþ0þìýªý{ýNý-ýý ýýý(ýMýoý«ýáý/þ|þ×þ9ÿœÿmàL¹{ÍMqŒŠ}Y#܆¯3²0²ÿ3ÿ·þDþÜýý5ýøüÐü±üªü³üÄüñüý_ý¤ýôýKþ¢þÿaÿÁÿpÐ v½B}ªÏïúúëË›dÈi‘«ÿ-ÿµþAþÑýqýýÒü™üsügübüü£üåü/ýýõýeþäþZÿáÿNË;£S˜Ëõ éÕZÓŽ7ê:äÿ‹ÿ1ÿÖþþ.þßý˜ýXý#ýõüÚüÅüÅüÒüîüýYý«ýþoþÞþZÿÝÿSÚXÐA£ø:oˆ–‹mCüµUòˆ£.Çÿ]ÿöþ›þFþüý¿ý‡ýcýBý1ý'ý(ý5ýIýfýýºýõý1þyþÆþÿrÿÓÿ*‘õ[¾pÀÿ6\lvbB Æq ™™—ÿÿ—þþ¸ýWýýÒü«ü“ü’ü üÁüíü/ýsýÉý$þ~þêþEÿ±ÿeÀc¬é+S†£¿ÏÖÕÇ´Œe&è•AÛu›ÿ&ÿ³þ@þÚýsý&ýÕü¦üyünüjü…ü«üëü8ý˜ýþ|þ÷þ|ÿüÿyómÓ6‚Æõ&(þÕ¢g#ÙŒ8ç<îÿ›ÿHÿøþ©þ`þþØý›ýiý:ýýýóüöüý!ýLý†ýÐý&þ‰þøþnÿìÿbäbÚL¬Izš¢˜xD¬HÞeïrÿÿŠÿÿ³þTþþ»ý…ýVý:ý$ý!ý%ý4ýMýmý—ýÆýþý7þ|þ¿þ ÿZÿ¯ÿÿÿT­ c» ]£Þ3IKAòªZö‡‹ˆÿýþƒþþý>ýðü¶üü{ü}ü‘ü¶üòü5ý‹ýçýMþ·þ$ÿÿûÿW»g«ð%Rz’ª³¸²¥‘qOè£^²Möÿ†ÿÿ¯þGþâý„ý2ýêüµüüzüxüü²üöü=ý¢ý þ‡þÿ‘ÿ—”d¹õ,@RE1 Ö”Oý¨Sô Cùÿ¤ÿUÿ ÿÁþþAþþ×ý¦ý‚ý^ýJý5ý5ý4ýGýbý‹ýÁýþQþµþÿˆÿýÿlídÛLªFž¤¡xJ¤BÈQÌJÐÿSÿÛþoþ þ½ýtýCýýýýüýý4ýXý‹ý½ýÿý8þƒþÃþÿXÿ¨ÿóÿ8ˆÖ%s½H‡»çøÊ?àx{ÿúþrþýý‰ý-ý×üžürüaü`üzü¢üâü/ý‹ýôýaþÙþJÿÉÿ' ù]ªð+Y{• © šlI&öÊ‹S ÂpÉÿjÿ ÿ¨þGþêý—ýEýýËü«üü‘ü¡üÆüýKý¨ýþþÿÿ!­5´+Žè(Yu|pO"à˜@ä¹W¥ÿWÿÿÂþþHþþëýÆýªýý€ýoýnýlý{ýŠý«ýÐýþAþˆþÞþ8ÿ ÿvêaÐ?Ÿ÷@qœ¡ L«@ÊFÁ3µÿ-ÿ²þ=þÙýý=ý ýèüØüÚüêü ý6ýlý«ýïý;þ‡þÓþ%ÿmÿÀÿþÿK‹ÕUšÑAušÃØèíßÊžh Èhóüÿ‚ÿ÷þyþúý‹ý"ýÓü‹üdüIüKü`üŒüÎü ýýôýiþìþjÿíÿ_ÓBžö7n˜°¾¾´ †a;Ûªp8ø¹r-êÿšÿLÿõþ¤þMþþ¬ýoý&ýüüÑü»ü¸üÃüãüýZý¶ýþ•þÿŸÿ#¶;È9«K|›”h4í‘4ÅXçuªÿIÿóþ¤þaþ(þ÷ýÔý±ý¢ýŽý‰ýˆý†ý–ýžý·ýÍýïýþEþþ¾þ ÿ[ÿºÿyâQº$€Ø Z€’‘vL°CÐEÀ(§ÿÿ’þþªýQýýÒü±ü£ü¯üÃüóü&ýný»ýþhþÃþÿxÿÈÿ^¢ç!YŽ»ë:UvŒ›§¤š‚a+òŸHßrûÿ…ÿþþƒþþ•ý*ý×üŒü^üBü=üRü~ü½üý{ýñýtþúþŠÿ“‡ïFÆçÿÿ÷Û¾‰_æ¨d*å¨g(òÿ°ÿoÿ*ÿçþ¢þ\þþØýšýeý6ýýûüôüùüý>ý}ýÍý+þþÿÿ#¯>ÄDµb™ºÂ³‹Q 8¼CÃDÖÿbÿøþþIþ þÏýªýŠýýsý|ýý”ýªýÀýâýýý%þIþtþ¥þÖþÿQÿœÿéÿ1çMª e´þ5axzi?®KÎP½*Ÿÿÿ}þõý„ýýÎü”ürücüpüŠüÁüÿüVýªýþxþåþNÿ±ÿ _±õ7j™¿àû%5BIQMI<%Ý¥e»[õÿ€ÿ ÿŽþþªý?ýêüšüküBü?üGütü¬üýgýçýhþüþŽÿ®8¹'Ò0FA* Ñ—Q¹f̓>ÉÿÿXÿÿìþ¸þƒþSþþïý»ý–ýiýQý8ý1ý4ýGýkýŸýçý:þ£þÿ•ÿŸ-·9¯j­ÒàØ²x'ÀQÊKµ5®ÿ6ÿ½þYþþºýˆý`ýOýGýRýaýý¢ýÍý÷ý(þUþˆþµþçþÿKÿ}ÿµÿîÿ'f¶ùS›õ>ŒÎ1KTK(õ¨LÚYÌ9¦ÿÿxþïýqýý­ühü@ü0ü9üWü–üÖü?ýýþŽþ ÿ„ÿöÿ]¼`¥Ñý+4982.$ ýéÔ²‘a,éŸHõÿ‹ÿ#ÿ¯þDþÓýrýýÈü‰ü_üPüQürü¦üöüVýÐýUþçþ„ÿ±GÏN³ Ioy[,íJç‹"ÉiÔÿ…ÿSÿÿêþºþ–þsþTþ1þþóýßý½ý¨ý’ýƒý|ýýŒý«ýÓý þZþ­þÿˆÿ„˜–`§ÙíîËšBâdâJ¹“ÿÿ‚þ þ­ý^ý&ýýüóüìü ý!ýTýŠýÂý þCþþÉþÿBÿvÿ«ÿÚÿ2a–ÌC‚ÀCµÝý  ô΋@Òc×L»ÿ$ÿŠþúýuýýüXüüü ü4üiüºüý“ýþ›þ*ÿ°ÿ1ª‚ÕLj…‚‡nbA(êÊ®sQ0Þ§n'æÿÿ3ÿÓþmþ þ©ýPýý¾üüuükü…ü¨üóüJý½ýAþÒþpÿ ¬Màkß@Š¶ÍÆªr+Ðhû„0Ôÿ{ÿ*ÿêþ³þ‡þgþNþ<þ/þ&þþþþþþøýôýïýõýýýþ2þ]þ–þáþ3ÿœÿwöu÷pÞCËèðÜ©`ùƒö_»{ÿãþNþÐý^ýýÅü™üü‹ü­üÔüý\ý®ýþ^þ²þ ÿSÿ¤ÿÙÿ;o‘·Ûû#FužÐÿ,`~¥²½±•g Ð^í`ÙÿDÿ©þþ‹ý ý¡üHü üéûçûüû5üüèüaýìýþÿ´ÿCÔQÉ!r¤ÊÓÔ½žtB × k@êÆ „Z: åÿ¯ÿnÿ*ÿÚþ‹þ2þâý‹ýBýÿüËü§ü™üü¿üõüDý¬ý&þµþNÿöÿ>ÕtícµðöÀp™’ ’ÿ'ÿÌþþDþþüýðýêýòýüý þþ.þ<þLþRþ]þcþkþtþ…þ–þºþÞþÿYÿ¤ÿ]ÒD¿2£ _¢Ñáݶy«#†æ4“ÿêþFþ¼ý6ýØü…üWü@üEüdü›üâüBý ýþ€þóþ^ÿÀÿb¡Ú$ANdm¡ºÑô /E\efU6Àe€uÿæþMþ¿ý9ýÃü`üüãûÔûÛû üMü±ü,ý¹ýWþýþ¦ÿHå}ýnÄ)</å¨bÆs-â§p@üÿêÿÊÿ´ÿ—ÿtÿQÿ!ÿïþ±þrþ,þäý¤ý]ý.ýýüèüÛüòüýTý¦ýþ—þ$ÿÆÿc ¶Mä[¿ 3=*õ¥?¿2šú`ÎÿCÿÁþUþùý¶ýƒýký_ýiýýýÇýòýþJþnþþ®þÀþ×þãþðþÿÿ/ÿJÿ}ÿ¯ÿùÿ=™þjÕD¦Q‹°·¨w/ÈJµb¸ÿÿWþµý*ý¯üWüüøûóûüKü™üýuýúý}þ ÿˆÿkÍ]‘¬ÀÄù®¡™””™¥³ÇÔãéçØ¸‹Iø“ ¨ÿ"ÿþþzýý’ü8üýûÖûØûðû/üŠüÿü‘ý/þàþ˜ÿFú¡;»(t¦½°–W´Pç}·_àÿ²ÿ‹ÿrÿ`ÿTÿJÿ?ÿ6ÿÿÿãþÅþþ]þ$þëý´ýˆý`ýLýGýXýý¾ýþ…þþþ™ÿ(Òz·@°CdW3æjÈiÃÿ!ÿˆþþ™ýFý ýêüåüðüýGý‡ýÐýþaþ§þáþÿBÿhÿÿÿžÿ¥ÿ´ÿ½ÿÖÿñÿD‡Ð(ƒæE¢ò9h……h4ÙoâFšçÿ1ÿsþÉý&ý›ü.üØûªû›ûªûãû0üžü ý«ýNþåþˆÿ™vÆý"/-üÛ°ŠgE4""(7?MHH- ׊8Óÿ_ÿÞþ[þÔýWýÝü€ü*üýûßûíûü`üÊüRýìý£þ[ÿØ•B×Z¸üý½hýyòy¬ÿSÿÿäþÇþ¶þ·þ¸þÉþÓþâþèþêþàþÎþ±þŽþbþ5þþÝý¼ý§ý¤ý±ýÜýþlþ×þVÿèÿ} Èiû…ìAm}e-ÐVÁ_¢èÿ1ÿƒþèýfýýü¸üˆü‚üŒü¾üùüOý­ýþ|þßþ=ÿÿÕÿ-EUVWOLMRhƒ²ê.{Ò"{Âþ1?D åŽå7‚ÿÅþþ^ý¹ü>üÊûûaûpûûâûIüÓümýþÎþˆÿ-ÒiãL”ÃØÒ·ŠP Æ€?Û¹¨ž¢¯¸ÐÑÞÌÀ_¾ÿMÿÚþ]þÝýgýóü˜üKüü üüNü üý¥ýJþ ÿÌÿ“WÂZÏ%XaM ¸>¹Ú@¶ÿ3ÿÉþnþ1þþöýüý þ/þVþ€þ¯þÏþðþýþÿùþêþÆþ£þyþQþ,þþþþ.þiþ³þÿ“ÿ®LòŒžQpyM ˜ d¤ÜEÿ}þÉý,ýªüIü üòûøû(ügüÏü:ý¾ýAþÉþGÿ¼ÿmªÖëòèÔ¹Ÿ„wjy†´ß'j¾UÃØÞ¾Š0Ã2”ëÿ/ÿsþ¸ý ýuüöû›û]ûQûaû£ûüŠü(ýâý¥þpÿ2ò¥@¿ a€a)Þ~ ®PìœZ(þÿ ">Zm{vf:½ÿbÿ÷þþ þ’ý)ýËüüWüCü[üŽüéüdýúý°þoÿ< ÝKßOšÁ·7Ã2‰Ö`·ÿÿ‹þþÂýýmýký„ý·ýñý?þˆþÔþÿPÿƒÿ”ÿ¦ÿ–ÿ„ÿ\ÿ4ÿÿ×þ¯þ™þþ þ¾þÿUÿ¿ÿ;Ç`“%ý@_U&ÑP¹ú1Uÿ¥þÖýý~üü¨û~ûrû–ûÙû?ü¾üUýñý›þ<ÿ×ÿWÍ+m—¤œ€T æ²_KIZ³óB‹ÝUy‚pAò‚þX·ÿöþ:þ€ýÒü=üÁûiû8û/ûTû ûü­üfý/þ ÿçÿº…Aß[¸æóÛšHÑTÉ=¶;ÚÿƒÿHÿ!ÿÿÿ5ÿ`ÿÿÅÿóÿ+4$ ÏÿŒÿ"ÿÂþGþÜýjýýÃü”üƒü”üÊü%ý¡ý>þöþ¿ÿe9ý®;ªèé©>­>o˜Ñÿ ÿ]þÆýSýþüÒüÅüßüýcýÁý.þŸþ ÿsÿÆÿ2AI, Úÿ£ÿ_ÿ-ÿøþÞþÔþâþÿTÿ´ÿ"«?ÜsÝ'?:¦*yÂÞÿ@þhý®üüœûQû2ûBû{ûàûeüý¿ýþGÿ®KÎ/rs9ñš<äŽKÿÿ7n¾c·÷.CDßvù[¸ÿúþ<þ€ýÑü9ü¾ûdû:û5ûcûºû?üæü¯ýŽþuÿcC$ÞƒøMjg,Ù[Ê#wÉ'˜ÿÿ¶þtþLþDþ\þ†þÈþÿfÿ»ÿþÿ3YhY5úÿ¦ÿ@ÿÉþTþßýtý!ýáüÇüÊüùüHýÅýYþÿÚÿ¬ˆ]'ÑcÃä†[–µÌåÿÿ*þvýÑüjüüüü9üüþüˆýþ³þCÿÎÿ6“Óô÷à­kÌÿuÿ,ÿñþËþÅþÕþ ÿ[ÿÊÿB×s¥/–å Ý{üL‡£ÀÿÍþãý ýMü­ûCûúúîúû]ûáû|üCýþöþ×ÿ¢jû9H6ù¦4¶5¬;ÕÿŒÿRÿAÿEÿoÿ«ÿÿÿYÁ*†Òá‡êÿ+ÿnþ®ýúü_üÞû†ûYûZûûòû€ü:ýþÿýÿðëÈ“0¨éÜ’|Ãü(^¢ÿöþgþõý²ýŒý—ýºýþbþÚþLÿÉÿ+ŠÑùë¸bÿÿ…ÿÿþyþýýŒý;ýý÷üýSýÅýQþ ÿÑÿªˆg3æyÜçî4Tdbmÿvþ—ýÒü;üÆûû{û¢ûðûiüý²ýnþ.ÿçÿƒÒóõЋ.¿CØÿaÿÿ¸þ“þˆþ¦þåþFÿÆÿNô™=ÒL¨ÜäºeÞ2dzÿþžý¼ü÷û\ûèú²ú§úÛú=ûÓûŽümý[þYÿD6¼I¥ÔÒ GÊ2‰Ü.œÿÿ¨þ`þ<þDþiþ¹þÿ›ÿ£#—í&7#àyîB“ÿÅþüý<ýüü›ûgû]ûûïû„üAý"þÿ('Ýò,0þ‘ÿ;eu„ ÿÂþþeýòü°ü•ü´üõü`ýæýƒþ%ÿÏÿ[äP”º®ƒ,º/™ÿÿþ\þØý_ýýåüñüý„ý þÂþ‹ÿkR<Òyß#"ô…ì60!ÿþ'ýeüÇû`û1û7ûwûçû‚üEýþÿÞÿ³s–äøÀ\ß>Ÿùÿ]ÿÏþ]þþëýôý'þ„þÿ¦ÿPÊ‘Üç£%|±¼ÎÿÁþÆý×üüeûíú³ú´úéúeûüàüÏýßþðÿøöÚ“ v”|-° Ft”Íÿÿ]þ×ý}ýSýWý‹ýíýkþÿ¹ÿf¯7ŽÃÅ–:¯7iÿ†þ­ýçü>üÀûnûYûuûÒû\üýþÿ &1*ø¡ B;îx½ëëæÜÿÛþçýýuü üÉûÌûÿûeüýüªý~þOÿ ç•%€·±’ë&kÿþéýGýÌüüaü€üÍüQýþÕþÃÿ¶´¥|0²ätØÿ ôÛÿ¾þ¤ý²üÚû6ûÌúúœúÑúGûÝû ürýVþ7ÿÅhä9^],ãtýv‰ÿ/ÿçþËþÓþÿþZÿÒÿaΔKù„ö3L,Þa·ì ÿþ;ývüæûrû8û%û?û‰ûìûwüýµý`þÿžÿŒß1/í®t,úÿÆÿ£ÿÿ™ÿ«ÿáÿhÃ&„ã/n”¤•p(ÎZ×H½ÿ'ÿþþ®ýTýý÷üíü ý6ýƒýÞýNþÂþBÿ½ÿ.TšÉéúóéÍ©‡U1༞…p[J8#ûÿáÿ¿ÿ–ÿoÿ?ÿÿäþ·þ‘þkþVþ=þ>þ9þMþ`þ†þ°þáþÿSÿ”ÿÔÿJ„¾ù)]ˆ®Ôí *4690* òÚ¾Ÿ[6éÙtJ&ãÿÃÿÿƒÿcÿHÿ2ÿÿ ÿ÷þéþßþ×þÏþÐþÌþÑþÕþÚþæþïþüþ ÿÿ.ÿ>ÿSÿgÿ{ÿ“ÿ¤ÿ½ÿÑÿäÿýÿ+7NWgtzŠŠš” ›¢›Ÿ•—‹ˆupcXS@<+# óÿîÿâÿÚÿÕÿÊÿÇÿ¾ÿ¼ÿ·ÿ´ÿ±ÿ°ÿ®ÿ°ÿ®ÿ±ÿ²ÿ¶ÿ¸ÿ¼ÿ¿ÿÇÿÇÿÑÿÔÿÙÿâÿæÿëÿóÿøÿüÿ  %"*%))&,"+& ÿÿþÿýÿøÿüÿôÿøÿðÿóÿïÿñÿìÿðÿëÿðÿéÿòÿéÿóÿìÿòÿïÿõÿòÿöÿöÿùÿøÿþÿ÷ÿúÿÿÿ       ÿÿÿÿýÿýÿþÿýÿþÿûÿÿÿûÿýÿýÿüÿýÿýÿüÿýÿþÿüÿûÿüÿþÿþÿþÿþÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿþÿÿÿþÿýÿüÿüÿüÿüÿýÿþÿþÿÿÿÿÿýÿÿÿÿÿþÿÿÿþÿüÿÿÿþÿüÿýÿþÿÿÿÿÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿüÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿýÿþÿýÿýÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿþÿþÿýÿýÿÿÿÿÿÿÿüÿýÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿþÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿÿÿþÿÿÿÿÿþÿüÿýÿþÿÿÿýÿþÿÿÿýÿûÿüÿþÿýÿÿÿþÿýÿýÿÿÿþÿýÿþÿþÿüÿüÿýÿÿÿÿÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿýÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿüÿýÿþÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿüÿÿÿÿÿþÿýÿûÿýÿÿÿüÿþÿÿÿýÿüÿÿÿþÿýÿýÿýÿþÿÿÿýÿýÿýÿüÿýÿþÿþÿþÿþÿþÿÿÿþÿýÿýÿÿÿÿÿþÿýÿüÿúÿüÿÿÿÿÿÿÿÿÿÿÿýÿüÿüÿþÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿüÿýÿýÿþÿýÿþÿüÿüÿýÿþÿþÿÿÿþÿüÿüÿþÿýÿýÿþÿüÿÿÿÿÿÿÿýÿýÿÿÿÿÿýÿûÿþÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿüÿþÿþÿþÿÿÿýÿûÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿüÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿüÿÿÿÿÿÿÿýÿüÿþÿýÿþÿÿÿýÿýÿýÿýÿýÿþÿüÿþÿÿÿþÿýÿýÿÿÿþÿÿÿÿÿþÿüÿýÿþÿþÿüÿþÿýÿÿÿÿÿþÿüÿûÿÿÿþÿýÿûÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿüÿýÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿþÿúÿüÿÿÿÿÿþÿüÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿþÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿþÿÿÿþÿþÿýÿüÿÿÿÿÿýÿÿÿýÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿûÿûÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿýÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿüÿýÿþÿþÿüÿüÿüÿýÿýÿýÿýÿüÿüÿüÿþÿýÿüÿÿÿþÿúÿýÿþÿþÿÿÿÿÿüÿþÿýÿýÿýÿýÿüÿüÿÿÿÿÿýÿþÿýÿüÿþÿÿÿüÿþÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿüÿüÿüÿþÿþÿÿÿÿÿÿÿþÿýÿþÿþÿýÿÿÿþÿýÿþÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿýÿÿÿÿÿþÿþÿþÿþÿþÿþÿÿÿþÿýÿýÿýÿþÿýÿÿÿþÿüÿýÿÿÿþÿýÿÿÿþÿüÿûÿüÿýÿþÿþÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿýÿÿÿýÿþÿûÿýÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿýÿÿÿþÿþÿýÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿüÿüÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿýÿÿÿþÿÿÿýÿýÿÿÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿþÿüÿüÿþÿþÿþÿýÿýÿÿÿþÿþÿþÿþÿýÿüÿýÿÿÿþÿÿÿþÿþÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿýÿÿÿþÿÿÿýÿüÿÿÿÿÿÿÿüÿÿÿÿÿüÿÿÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿÿÿýÿÿÿýÿÿÿþÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿüÿûÿþÿþÿÿÿþÿþÿýÿýÿüÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿüÿÿÿÿÿÿÿÿÿýÿýÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿþÿýÿÿÿÿÿþÿþÿþÿþÿþÿýÿÿÿþÿýÿþÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿúÿýÿþÿþÿýÿýÿûÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿþÿþÿýÿþÿÿÿÿÿüÿûÿúÿüÿÿÿÿÿÿÿÿÿýÿýÿýÿÿÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿÿÿþÿÿÿýÿþÿÿÿýÿüÿüÿüÿýÿÿÿþÿÿÿüÿüÿþÿþÿýÿýÿþÿýÿüÿþÿþÿÿÿýÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿþÿýÿûÿýÿýÿýÿþÿÿÿÿÿþÿÿÿÿÿþÿþÿþÿýÿþÿÿÿÿÿþÿÿÿþÿÿÿýÿûÿýÿÿÿýÿûÿüÿþÿÿÿþÿþÿþÿüÿüÿþÿüÿýÿýÿýÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿýÿþÿþÿüÿüÿüÿþÿÿÿýÿýÿýÿþÿÿÿÿÿýÿþÿÿÿÿÿþÿÿÿüÿüÿýÿÿÿþÿÿÿýÿüÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿþÿþÿþÿþÿÿÿÿÿüÿúÿûÿýÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿþÿúÿúÿþÿÿÿÿÿýÿýÿýÿýÿþÿÿÿÿÿÿÿþÿüÿüÿÿÿÿÿþÿþÿÿÿþÿÿÿüÿýÿüÿûÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿþÿþÿÿÿþÿÿÿþÿýÿÿÿýÿýÿýÿþÿÿÿþÿýÿþÿþÿýÿþÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿþÿýÿüÿÿÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿþÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿüÿûÿýÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿþÿýÿüÿýÿýÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿüÿþÿþÿÿÿýÿýÿþÿýÿÿÿþÿýÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿûÿûÿþÿÿÿÿÿÿÿýÿþÿýÿüÿÿÿþÿþÿÿÿüÿþÿÿÿþÿÿÿýÿüÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿýÿüÿÿÿþÿÿÿÿÿýÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿþÿýÿûÿûÿþÿþÿþÿÿÿÿÿÿÿÿÿüÿüÿûÿýÿþÿüÿýÿÿÿþÿüÿýÿþÿþÿþÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿÿÿþÿüÿýÿýÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿûÿùÿûÿüÿþÿþÿþÿþÿÿÿýÿüÿþÿÿÿþÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿþÿûÿûÿüÿþÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿÿÿÿÿüÿüÿüÿûÿüÿýÿþÿÿÿþÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿûÿüÿýÿÿÿÿÿÿÿúÿüÿýÿÿÿýÿþÿþÿÿÿÿÿÿÿüÿùÿúÿþÿÿÿÿÿÿÿýÿûÿúÿüÿÿÿÿÿþÿÿÿüÿûÿýÿþÿÿÿýÿúÿýÿþÿÿÿÿÿþÿÿÿþÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿüÿüÿýÿÿÿþÿþÿÿÿÿÿýÿüÿþÿüÿÿÿþÿÿÿÿÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿÿÿüÿùÿþÿÿÿüÿüÿüÿüÿüÿýÿÿÿþÿüÿûÿýÿÿÿÿÿÿÿþÿÿÿýÿüÿüÿÿÿÿÿýÿýÿýÿûÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿüÿûÿüÿüÿüÿüÿýÿýÿýÿüÿüÿÿÿÿÿþÿþÿüÿÿÿÿÿþÿþÿþÿÿÿÿÿüÿýÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿüÿþÿÿÿþÿÿÿýÿüÿþÿþÿþÿýÿûÿýÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿýÿýÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿýÿúÿüÿÿÿÿÿÿÿþÿþÿþÿýÿÿÿþÿûÿüÿþÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿüÿÿÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿüÿüÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿþÿýÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿþÿþÿûÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿþÿþÿüÿüÿÿÿþÿþÿþÿþÿÿÿüÿýÿþÿýÿþÿÿÿÿÿþÿýÿýÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿþÿüÿþÿÿÿýÿþÿþÿýÿýÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿþÿþÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿýÿûÿýÿþÿþÿÿÿÿÿþÿüÿüÿþÿþÿþÿÿÿþÿýÿþÿþÿÿÿþÿþÿÿÿýÿüÿýÿþÿýÿýÿþÿÿÿþÿýÿÿÿÿÿþÿýÿýÿýÿýÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿ Tµ:ê¤i Š¿«=‡…Núÿ‹þý»û~úfù‘øë÷›÷„÷É÷Løù7ú†û ý¯þY°1x„:¢­`¾Ñ¢BÀ/®ÿ9þñüãû û³ú úïú–û—üãýhÿÔ›>´Õž ì » þ°Û}·‘ý#ú‘öøò„ï[ì—étçóåSå屿ÃèÎë½ïnôÚùÆÿ€ ìÞã#p'*g+ç+g+ÿ)"'# %¢Ãü¿óäê}â Û‘Õ¶ÑÈÎìÌ%ÌÌÎÀÐuÔ¥Ùîà¨éùò«üSĦ« û&^+P.30ô0ž0-/¶,=)/$L¯² ¢ÖýröÐïêqåþáåß߈ß3áôã¥çìþð3ömûgïÍÌ Ç ªfû ~ ºéý­ømó\îÚéæYãÈá’áÁâ`ådé¹î7õµüÝ” h¹&_,½0+4q6|7$7n5B2Â-¡'ˆV4|úƒí»ààÕÎoÇÿÂ6À[¾Ž½Ó½,¿™Á[Å_Ë\ÓÏÝÉë^ú –%©.o6Û;.?`A€B†BƒAn?k<–7f0(_R'Xõ/éÞÌÕ8ÐàËøÈšÇÇ’ÈË·ÎIÓÙïààéøòàû>Ü kÈ»JZd’ÔKR éþ½ù-ö†ó÷ññVòKôU÷\û€2 ÷Ð#ß$j%µ$"$`m Œøî-äÙÚáÓbÎÍɾÆýÄUÄÛēƻÉÄÎ Õ Þê!÷¸ +83Ì9>ð@ÈB’C9CÕAO?·;Þ5Ñ-Ï#Ð<ø(ê~ܾÒËxÅóÁο¶¾·¾¾¿ÏÁÅÊôÐÙ\ä›ðìüÍ-u&,Ó/S2ƒ3a32†/ ,\'!^t ûýôèïìvéAèOè¢é ìeïvóøÌü†úë  Qvn,º  ‡ÿù‘òìœå¹ßÑÚf×/Õ6ÔMÔŽÕ[ؼÜxãšëãô!ÿß öâE)0à5:Ò<1>£>>yg?g?[>n<á8£3- %8Î…«ø“î‡åËÝXØÔÔÚÒÒƒÒÔ’ÖÚøßaæ+íô¯úÎEÎ G™¦‡0È € {dý¿øsô¨ð°í¢ë¹êë”ìlï‚ó²øÚþ´ ¨.#•(u,S/1Å1.1R/,,i'8 Þ\ óõöèÝÔáÌ ÇÃÂÀ]¿ù¾«¿aÁKÄ É/ÐØØRåcóîžðÓ*e3::”>ŠAhC2DÑC]BÕ?Y<½6×.[%2R jüàîâi×(ÐUÊ]ÆÿÃÿÂÃ2Ä’ÆPÊÏ¥ÕÓÝè_ò“ü1Ù_q"œ%='Ž'£&“$!v$_z ®O“û¨÷¹ôçò@òÂòdô ÷’úËþo[: ËÉ÷À ô„ß $þRö²í å¤Ü!Ö_ÑzÍÊôȑȗÉñ˼ϼÔîÛCææñZþ< 6´$Ï-^5ý:©>AˆBçB)BV@v=ë8à1Q)ç…±ÿäð{â3֤͢ÆÂ#¿@½j¼Ä¼.¾«À4ÄËÉwѲÚVç¶ôðÕÕ`%ž,ø16y8t9M9 8T5_1,N& Ø¡ °aúÜòuìGç†ã+áFà¸àwâJåé‹íxò˜÷ üKi¿ k i B6…ýEøØòbíHèºãàYÝÜýÛuÝuàöäãêòMúYí Âl ®(´.Ì3Ö70:y; ;’:X8<4¤.d'Ì@ò-õtçjÚ Ñ5ɦÃ0À¨½4¼Ï»”¼m¾\Á­ÅxÌÕùàqïZþ' Ž&(â08Â<Ÿ?tA9BðA’@@>¢:5µ-¾$—í xÿwóUè[ÞåÖýÑ{Î<Ì_Ë¿ËaÍÐÉÓ©Ø=ßç*ï$÷¼þ £ šL¼Õž4¶WR âHÐþ ú÷(ôKònñÈñPó÷õÅùqþáã %qlß!&ø(Ÿ*(+‘*¤(%%’E£—û¿ðÅåCÛqÓÍÙÇcÄVÂQÁMÁIÂrÄ*È*Î~ÕàHíQû» ¢%R/o7è>@6;<á?„BDuD¼CòA?;ß4»,~" ^ßùäìÚàוÐpËÓÇüÅOÅÍÅ^ÇPÊžÎÅÓSÚãhì¿õÅþ›ýÊ Ç 43MÄÚ Éá]ÿoûIø öýôõ*ösø¢û´ÿVk ©Æ† Õ÷!Ë"@"4 ª­X× Y,ø‰îËävÛjÔãÎ9ÊûÆÅIħÄ/ÆÉäÍÔ^Ü<è!õ´šd?*Â2Ï9e>A´CÂD­DxC'AÒ=Ç81¨'He OüXíùÞÙÓŽË9ÅJÁ«¾&½º¼k½&¿ßÁðÅÌßÓ½Ý|êi÷,Qò$++0†3y56g5w3n0m,H'` Iù`zù‹ó°îëÉèÈçèéìZïaóÆ÷Pü®­¥ G Ì 8 v ŸÂ ÿ¡ù·ó¥íšç÷áöÜmÙÿÖÁÕ¶ÕÙÖ{Ù¼ÝäÕëÈô»þF - (ƒ/5ò9Ü ?¦>==n:Ý5=/ó&î4 ÝþDðåá«ÕÛÌ»ÅÁË½Š»eºkºŸ»ï½UÁ'ÆÍ¶Ö¯ãnòf0W*"2¶8ö<|?û@lAÉ@(?‘BBŒD²E¸EšDYB?t:@3]*íwÔòÖä䨫ÐÊÅÊÂhÁ Á«Á9Ã(ƖʉÐ~×ÿàÖë¸ö- å’Ï!&¢(Ò)±)S(Û%8"QÆîú A÷jü¯øölôô¹ô}ö3ùªü°  Ú ÁúO˜¥oÖõË —vþªömîæìÝA×_ÒkÎo˘ÉùȺÉÒËRÏÔéÚÎäJð¦ü— »¥#7-5;ã>AFCëCjCÓA)?;;ò4,O!²kôóä†×*ΉƟÁB¾ó»Åº¸ºÕ»¾3ÁºÅ¨Ì<ÕíàÒîíü© ÅÃ#,G27ú9„;é;;=96o1ñ+%Ô*kÿööuï)é0äªàŸÞ ÞØÞåàäè¬ìªñ¼öœû ÔÕ×Î ¦ cÓÚþ>úOõKðrëç\ãšàñÞÞ©ß3â:æ ë[ò(ú×+ É_Æ'ü-&3b7ê9c;¿;ï:ð8M5ï/6)"®Jk÷[é¼ÛÈщÉÃÿñ¼%»zº÷º”¼W¿ÃéÈtÑëÛ˜êöùa ‘g&08?=•@æBD*DCAõ=o9¡2z*[/ïøÌëà¾×ÓÑpÍeÊ»ÈtÈ~ÉÀËÏ^ÓÎØà`èÌðù²¦¡ rý1¨{ ³Gÿÿ)üíø‚öõÂô‰õ{÷{úpþ0‘S7ë8Ã#Ç&Ä()/)n'S$#U*ݹüÿñçOÜ5Ô´Í'ȃÄ: ÁÎÀšÁgÃÝÆMÌqÓÚÜ ê0øØ¥ $p.7þ<õ@ÜCÀEuFFnD­Aô=s8!0ü%Ë [ùnê<Ü9ÒJÊšÄ!Áྴ½ ½™¾˜À|ÃÈéΩÖaá™íÏùŸÁä­#Ä)•-/0r1z1L0.è*z& ˜a> tTþù³ôñ†ï½î#ï¥ðóUöú;þ_Yæ È ÎÓ´bâ 6‚êýš÷ÎðÕéòâxܘ×ÔŽÑмÏгÒÖsÛfãîì‰÷ðáõR&§.¾5ø:d>š@ÚA B)A=?4<27©/j&_ :ûì3Ý,ÒPÉÃþ¾õ»º?¹¥¹;»â½›ÁÓÆÛ΋Ø4æõŠ: ú*—2³8–<Ç>æ?@?.=÷95¹.6'ÖÀü/òVéÉáÏÛØÂÕâÔ'Õ{Ö'ÙßÜâÒçßíæó®ùîþq· 9 ‘ Î úEÖæþ«ú`öLòµîÊëÏéæè8éÐê¼íìñL÷´ýïÅ ñÍ$©*/§245‘6¨6`5¹2¾.d)E!Н þêðÀãà×KÏçÇäÂ’¿,½Ò»›»x¼Œ¾£ÁQƔ͖֤ã¹òJÜ !¿,µ5M>9|16(8ç šþ«ðŽãcØÔÐÛÊ»Æ?Äà ÃýÃ-ƕɛÎvÔÜÛžå˜ïjù«1 ¬êÇ#!þ"X#V" ϸúà ö…Åüáùõ÷#÷e÷Äøû`þRΜ iü_¸æ¾75Èþü ó%ùÕïFæèÜ‚ÕéÏ˃ÇcÅUÄhÄ®Å$È Ì…ÒMÚªå‘ò8[g)ý1€9s>ëAkDÍEF0E0C @¿;á4½+la¾ðŒá Õ ÌÅ®À™½œ»Éº»~¼å¾]ÂVÇßη×ä ñ*ÿ= }—#M+Í0ô4¼7É8¼8›7ö4Q1¸,'gÁ¤Üý×öèð'ì·è¡æâåhæèÊêIîYò´öûMÿW È ÚȰ·ÿîú¢õðXêçäûßãÛJÙ³×N×0ØjÚWÞ0ätëô‘ýÛšnI'.¾4ƒ9·<|>U?,?>®;¹7]1³)U“(óMä ×ÍèÅàÀ<½¡º!¹Ô¸¬¹¹»Ó¾ÃUÉiÒÚÝí´üC W†(–1í8¦=«@ BC=CîA˜?Z<:7î/z'â@®ªöjë]áHÙïÓIÐõÍíÌ*Í–ÎцÔ3Ù`ßžæîPõ/üb¾ 9ÔP¿?  ?6.þYúööIôvòµñò¡óTö1úÿ©ü «xô$k)v,.¡/ˆ/C.º+ 'L!¤²® øôëñß¹Õ6ΨÇ;ÃhÀƒ¾£½Ó½¿uÁ"Å ËÓ¤Ý ì6û· %(ù1û9+?îB£E5G–GÈFÌD´AŸ=¶7ß.1$aÝö(èµÚ\ÑíÉÁÄÁ¸¿å¾¿XÀŠÂÆ`Ë*ÒDÚ)åªðü×ܾC!¢&*é+ˆ,,*½'ê#ˆ—[0 M{üâøLößô‘ô_õ5÷èùUý-Tp N §AîÚöÀW ¼8ÿÞ÷ ðòçÿßÙÑÓ·Ï’ÌyÊ’ÉÊÂËíÎdÓªÙòâîCú#k”! ,+4¥:Ü>ÜAàCÐD¥DRCâ@_=8Ã/¦%A¾ö÷5è™Ù7ÏÓÆ_ÁŠ½Æº)¹·¸v¹W»V¾JÂÈ‘ÐÌÚæè–÷;!9+U28u;h='>ë=ºž@*B¨BBl@²=P9m2Û)Gdãþ1ïÂß|ÓÊ0ú¾B»é¸º·Ã·û¸c»Ü¾XÃYÊÄÓ3àœïAÿ¥aÐ)A29s= @½ABB²A@=¼9÷3À,ý#?[ ¼Èõ¿ëïâ®ÛåÖøÓfÒýѿ҅Ôd×wÛá.ç”íãóÞùAÿÒnù Y — · Þ$ÇûþôúüöHó+ðÉílì#ìíMïÉòq÷1ýÏ& îÖ•"Ñ(u-(1ó3“5 65è2G/]*#¥ €wó+æªÙТÈ1׿ë¼C»¾ºN»½ä¿ÓÃFÊÓÏÞ#îþ/ <+Ü44<Í@UDÉFHHëF D:AéBåD¤FGG±FïDB >K8|/¦$T,ÝôÒä¹ÖóÌ3ÅMÀ¸¼?ºï¸Î¸á¹ ¼Q¿wÃúɳÒyݘëáùèMž!Ù*31A6h9; ;ú:A9L6Ù1—,&u( HNú7óEíŸè[å…ããìãéåàè‹ìÃð/õžùÈý^RVcV/úÄÇüøöò§ílè‘ãRß Ü-ÚkÙàÙ˜Û(ß[ä ëþò üïo&f%-n3¨80<<>Y?z?“>¦< 9N3í+º!”öjç8ÙúÎ‘Æ Á½º ¸o·ò·«¹¼†À÷Å^ÎàØ¶çÒ÷ôÅM&…0¼8>œADhE•EšDŒB€?_;û4Ã,€"7ÜßúšîiãùÙ™Ó ÏÛË ÊžÉʖ̺ϽÓàØ®ßˆçxï#÷Nþ£ HG“ñ:¤M ŽŠ¬ÿüôøšö)õÇôõd÷húrþ` 5 "Û&o*Ä,.Z.q-J+š'Î!º<£=úYî[â–׮ϰÈÎïÀ€¾U½8½6¾HÀjÑÈgÐÚüçI÷çã%–0K9?2CgFaH5I¿HG>DP@6;63:) , Dû­ëëÜZÒ ÊEįÀA¾ì¼±¼“½{¿ZÂ¢Æ Í¦Ô„Þ°êâö²Ë á› "']+ñ-F/u/r.y,|)"%bçNÊ ¸C¬ûøˆõ3ôüóîôÒö“ùðü¨•jê ÖøésÅ ë aù òdê§âdÛ½Õ—Ñ1ÎÔ˕ʟÊüË·ÎÊÒ„Ø$áîëá÷šÏk*Ô2Ï9{>½AD^E†E‹D`B?k:ó2•)ê# èûëÚÛ“ÐhÇlÁ ½ì¹Ø·ü¶T·á¸™»c¿CÄæË‰ÕÓâ/ò‰‘ÄK*:2’8¨<è>'@U@ƒ?À=Ñ:T60)ah ÿfõ¾ìYådß0ÛàØâ×2Ø©Ù,Üààäêƒïâôóùsþ&ñµ]ïwÝÿü×÷yóJïkëHèôå»ä¹ä æÀè×ì>òÞøpäÎø÷#ß*J0ç4a8Y:Q;;À97i2_,6$W5 Mýñî£à®Ô®ËÄí¿m¼é¹Œ¸W¸T¹†»Ò¾8ÃÊ ÓZàeðà]b!-7ƒ=×A"ECG1HëGoFÜC:@†;:4+ùNó²åóÙìÑÂËDÇ ÄTÃ#ÃÄÆZÉ"ÎÊÓ¹Úæãíóöáÿÿˆ¨PšŽkAr“ ìWÿxü|úŠù¤ùßúýPOòï  ¡ƒ w#%l%œ$A"&„y0 íÿâõeëÒàu׉ЂÊþÅúÂIÁ‡ÀÅÀ€ģÈ2Ï=×ãBñ$j¤a+ë4I<ü@µDZGÛHI-HF®BQ>(8Ã.#ùtòâàÔiË?ÄÇ¿„¼Xºe¹¹õº]½ÐÀxÅÌ2ÕÒà„î7üp Þ!ª)?/3k6Ð7ê7½6O4Ó0y,þ&Ë w Qéùuô9ð8íë ëéë»ínðËó™÷’ûyÿÿ@Ž Ð õîÒ¼ÿÁúõïÏè²âõÜ©ØqÕyÓ~ÒžÒîÓyÖôÚ«á&êóóÉþ\ PD"µ+*3]9‹=O@"BòB«BKAÎ>;Ù4ˆ,d!œþúòãGÕZË£ÃǾ庸¶¶·¹_¼´ÀŠÆŒÏ–Ú ê2úV ô'‰1-9>I QèÑ×ÁnËÃeÁ òCüÌóîê÷á²ÙmÓNÎÊÇyÅîÄÅTÇÐÊíÏnÖAà©ì#ú>ª·$/·7•=¹AñDGHÞGmFÌC @ÿ:ÿ2Õ(3± ùøJèÙ5άÅ2À,¼2¹n·Ù¶„·h¹g¼xÀËÅÎã×¼åÁô¦ t,*c1P7å:=é=Ì=Ài?Ñ>/=:5é-Ò$˜% ú›ê•Û Ð’Ç„Á$½À¹{·g¶Š¶î·…ºE¾ ÃzÊ„ÔPâÊò”4$[/_8>>NBCEG§GGSE~B¸>{9Ÿ1D(Q4 Fÿæñtå©ÚEÓíÍåɎǦÆãÆ/ÈõÊÊÎ~ÓIÙùàxéîñú_çP ˆqXj€ª6 X Sn÷ýûæø®÷÷„ø úÍýëát cpK´#'u*,¼,:,“*C'"©Æ®«üñ åØÙpÑHÊßÄTÁå¾i½½£½l¿@ÂÇÆëÍÔÖðã=ó%R4#ä.f8­>CCÕFt7-Î zíÿŒï×ߟӑÊéÃá¿î¼)»ƒº »¦¼H¿Ô ȯυ،ä’ñXþ ¾·v'ˆ,ö/2Þ2u2Ì06.¬*â%Ÿ—{ ;¢þîùKöÚó‘ò‚ò€ó{õCø˜ûSÿ·ñ ˆ F› % $ ûcô4íÕåÞxØÝÓSиÍ#ÌÍ˵Ìü΋Ҥ×tßÃéOõÊÖ3(1£8½=XAùC“EF^E‡C†@|<à5À, ¯jïßQÒ[ÈÃÁ½T¹Î¶|µzµ®¶'¹¸¼WÁ¡ÇѽÜìµü• ×å(Ë1ã8v==@ÿAŸB*B±@=>œ:5.£%wÑg§øÁîæåÞÅÙƒÖëÔ‡Ô7Õ×Ú,Þtã/éï³ôöù”þV!á~€ðÿ9ü9ø'ôRððìEêŠèäçƒèuêºíUò%ø ÿÚIè v(.å2Ç649n:œ:9W73†-&=“SòããÏÖlͣňÀ±¼Ú¹¸‹·-¸º½BÁ#Ç4ÐŽÛ’ë\ü@ ëº+ë5<=BÔEeHÏIêIÒHƒFC¨>Ÿ8‹/›$Ž3÷»è‚Û_ÒIË0Æ ÃoÁÜÀMÁ©Â9ÅɾÎ*ÕaÝ«çëñÓûþB N]2!x"P"Ó 0§mÑ e r¢ý°ûÕúûRü£þÇ·* æª0-k !¡"I"o :ïW ª(øîÌã Ú¦Ò|Ì]ÇôÃòÁëÀÜÀÒÁÛÛǚÍÕ÷ßËí¤üë X>)#3<;w@–D¤G†I3J“IÀG±D†@;}2›'('öjå°Ö‚ÌŽÄŠ¿À»¹¡·k·k¸™ºÓ½ÂÙÇÐÎÚåèY÷‰lK)Ê/á4d80:Ë:G:§8°5q1a,$&õg &£üö¤ð{ì¯é=èè#é:ë î²ñŸõ®ù›ýû *7+ûÉ¥ü½÷?òvì æáÜrØßÕÔHÔ$ÕU×4ÛJáéYò§üÎrEœ)51ò7™<˜?¶AÔBçBÕA¬?p<7û.ï${ѪölæŽ×͉Ä#¿Ýº§·ªµÖ´[µ·º:¾]ÃnËØÕ—äPõ'¨è%‡09o>$B¿D.FrF”E”C™@¦<½6x.Õ$Äp vý(ñæåÜYÕÛаÍßËfË2Ì$ÎÑãÔóÙ‹àìçPïböéü•Tô c —Š { ¯E˜×ýNú)÷½ô"ó–ò#óîôá÷ü!Ê × #(µ,è/)2V3H3î1B/=+?%N£Ò4ùìóÞAÔèË7ÅÁÀ‡½5»ºì¹»D½®ÀvÅ.ÍêÖ-åpõ6Ç&ò1Ý:—@E_H}J`K÷JKIlFfBi=6Ñ+0Þ |ýqí@ÞôÒoÊDÄÀ¾œ¼Q¼½ø¾¿ÁÈÅÛËWӊ܈èœô0% û‘x$ó(¡+ì,-,/*ï&¥" ) Â<ýcúªøø’ø!úˆü³ÿN>* à ƒdƒRÃø ôúý(öÂí!åŠÜÇÕœÐ,̰ȹÆÞÅÆÇvÊ#Ï%ÕíÝàé÷ñR«!ø,ý5¿<(A³D&G„H HG:EÎA9=U6f,mNý&ìžÛ×ÏmÆWÀл`¸%¶/µyµ ·Ê¹¡½rÂ]É,Ó·ßkï%ÿyò!)Q1ÿ7><¨>ù?D@€?Ñ=ù:©6™0Ð)µ  Uøªï¢èúâÜÞNÜnÛËÛvÝVà$ä–èjíXò÷wû/ÿ óÓ˜HþØýüùŸõñsì(èpä„á¥ßß¾ßíážåÂêNñùë† –À¶(`/65¨9©û>²>^=°:=6–/A'ý ´ý4îÆÞ©ÒÉL ½Ó¹0·±µyµ‚¶Ï¸L¼åÀ/ÇÕÐݱííþ.ð É-¬7,>´B+FtHIMIãGME¦A=I6-X!žÝŠõöç²ÛDÓÍ7È‹ÅÄÒìīÆ×ɃÎíÓ©Úfã›ìŽõøý’% ˜®i»·ƒ;*uo LZÚÿüüìúáùÜùûú0ýaˆf Çn`$G'“)•*Š*D)t&ä!3Œ ÿìóOè¦Ü­Ó\ÌZÆPŸ¿Þ½ ½r½æ¾nÁgÅÒËWÔ-àRïEÿ…¯È,ë6ú=óBêF¿IVK­K¶J|HE@Ÿ:p1ç%¯“óã8ÕpËöÃ`¿å»¢¹‹¸¯¸ú¹_¼Ã¿&ÄåʕӄÞ;ìæùoœ…'s-¾1¥4.6T6*5Û2†/d+&S¬aµíû)÷‹ó-ñððEñ`ó:ö§ù\ý™£þ q à * E /ÙüãöOðhésâÏÛ®ÖñÒÐ0ÎqÍäͩϼÒH×XÞÿçó ÿÅ Ù~%Þ.â6®<@zCbE?FÝEbD­Aë=E8Š/•$ñMXó}âWÔ×ÉaÂ;½!¹$¶`´ð³Ç´ë¶Eº´¾?ÄçÌÑ×4çî÷’±)'19>XA™C¨D£DuCEA>š9á2ñ*ƒ ¼æûåðç“ÞyØ’ÔHÒ>ÑbÑœÒÓÔ(اܖâßè.ï9õÄú”ÿqL ›ƒíXýzù§õòïÞì‘ëtë‰ìúî¯ò¯÷ËýÕ¨ ïhe%Š+i0|4–7%9©9 9*7v3\.’'i©“õ2ç}ÙÏÇoÁN½º¸·f·ë¸¤»Š¿¸Ä÷Ì×ÎæÚ÷5 sÌ)…4½<ÿA9FHIK¦KæJìHºEzA8<4¶)=( 3ûÄëHÝæÒËMÅÏÁ·¿°¾Á¾Ñ¿ÝÁþÄÃÉGЫץá³ìŽ÷ÔH œœ þ#é%‰&è%4$!OA-? Ìþ,üQû‰ûßü$ÿDT Ê1D¼aî>+œœ#\ dˆúìðýæúÜÕÔÎ\ɃÅù®ÁIÁòÁ’ÃíÆGÌ`Ó÷Üjêù<Å€&51ó9Â?&D’GÓIâJ¨J,IoF…Bˆ=6›+7 ú'éÙÜÍÅp¿&» ¸#¶†µ&¶¸»¿ÄîˬÕãNò^æq®(,0*6:s<\=J=><é9j6Y1+Y$÷r0 ÿÛ÷@ñÛëáçOå)äZäÄå3è~ëUï…ó¿÷ÅûUÿ36B6 ךþˆú·õzðýê›åˆà,Ü:ÙM×sÖêÖ­ØÝÛ?áQèÍð„úaêÁ&Ú.Ü5;–>õ@]B¼BB.@G=’801ö'cÓ œú+êaÚÏÈÅÌ¿»…· µå³´rµ¸¼úÀ°ÇéÑß4ð¡åv#7/‘8’>ÐBíEÜGŒHHSF€C¹?¹:23*¤Œ4ô¾ç ÜãÔŽÏŠËþÈìÇ!È”ÉHÌüÏyÔ<Ú­á´éñùãÿÄ— 4Œ˜m.ñ  „É ü–ùH÷ñõ–õmöaø‹ûÆÿìå \ ×%Ê))-²/61œ1½0˜.!+À%£®nLüqïlâ­Ö&ÎÏÆÙÁV¾¾»2ºÄ¹„ºp¼‰¿¶Ã¥ÊÔíàñé×#û/¼9@ëD¬HAKLLë8Œ/¼# ¡ðç޾хÇÏÀÍ»æ·,µÅ³©³â´W·ýº§¿®ÅàÎKÚêŽú» >Ë'ÿ0g8=@×AB-B¼@a>Ó:Ž5–.&µF ±ú"ñÜèôá¬ÜŒÙÝ××^ØWÚzÝÞáÙæ*ìyñö"ûÿóèÍŠBöäý#úõõ ñbí…éLæïã±â­âäèæ2ëæðà÷òÿâg?›%Â,®2Å7;:=8>@>F=û:&7ó0f)ù8ÜñWâÿÔË_Ã[¾Eº>·^µº´iµT·ºâ¾yÄPͧØ×èoú) “÷+Š6Þ=éBÒF—IKKK;JòGD@F:1Í& p.ù„êÝnÓRÌúƦÃÂfÁÄÁÃ£Å‚ÉøÎ4Õ Ý çæð]úí šäÉ)° [áÖ… + nˆþ|üvûƒû°üïþ.ä S{E[#&°'+(a'8%G!m T vÈöë#à.ÖÓÎ0ÈðÀ§¾˜½•½¯¾ßÀLÄúÉÒ‘ÜjëFû˜ ‹*5 =_B±FðIñK­LL5JG¿Ba=O5a*ýo Ë÷uæ ×dÌ'Ä¿»S¸È¶‚¶p·”¹Ç¼ûÀŽÆùÎöسæ2õeãPˆ'Y.v3)79¤9 9‹7r4Y0+W%iÑ -þ/ø_óÊï‡í‘ìÖì:îŽð ó3÷ûÏþDCzÊ #á¥þù›óAí®æ2àsÚÖñҼЕχÏÂÐBÓ7×}ÝcæÀð9üŒT?"g,¢4!;q?£BàD FFæD’B?":+2 (B›‚÷Læ·Ö¶Ë/è½¹³µ†³­²%³ô´¸<¼|Á½ÈwÓ§áäò?7%0ê8|>_BE¢FñF!F$D0AL=¿7¦/I&^ wÿNó3è~ÞY×ÉÒ«ÏìÍoÍ=ÎÐÓ¼Ö×ÛrâXé,ð¦öƒüƒŠt& ´  yüÒIÿûÑ÷zô¹ñÎïàîïŽðJóU÷ƒüÃÒ ‹ˆ–!](„-Á1 5i7R88„6_3Õ.Ñ(¡ãì ùÚê–ÜéÑíÈ¢Â5¾ººF¸û¶ä¶¸xº¾ÆÂùÉ Ôâ(óÑ‚'Ã2é;²AZFèI+L,MÐL%K:H"D?48ò-õ ^£ÿGï²ßÀÓÿʟĹÀ ¾¨¼H¼ ½Ô¾Á€ÅbËÌÒ¨ÛNçógþù“á¦!O&)i*r*d)'Ü#+àL¾u ºžýÄûÞúûhü§þ·i » Ï|€›šUª’% óüôˆêÛà(ØÑüËsÇ|ľÂÂ`¯ØÆYËòÑŸÚCç{õqÝB#Ê.L8º>lC;GÓIMKoKVJìGLD†?9/A"×úþí×Û–ÏØÅ¢¿Ùº;·à´Ë³´’µN¸4¼ Á”ÇPÑIÝ'íý’ 1Æ'B0#7Ž;&>‹?Õ?)?x=ª:^6u0Ø)!¨u ¼Øùõñbë)æzâ=à„ß à âðä³èôì€ñö@úóýèù ûÒ–lýkùÈôÈï¤ê°å)ádÝÚÚˆÙ_Ù|ÚݳáàçŠïvøk( S‡#(,<3.9A=Þ?šAJBðAs@ã=¹9 3x*ý³žþî¬ÝDÑMǸÀ¯»®·Ï´2³è²õ³S¶ð¹µ¾³Ä#Î(Ú&ëýìN ®-ë7‰>CCàFGIrJPJòH`F½B!>â7–.Ž#³Ìe÷ËéoÝ’Ô[΄ɟÆ)ÅÚĸŘÇðÊqÏ´ÔOÛÙã—ìõý óu¨x Ò % Agæþéû°ùgø7ø"ùCûyþ´Òž ×8u Õ%ü)Â,«.{/,/-¸*ö%Àƒæ Eÿ×òæÒÙ¸ÐÍÈ7Ãq¿”¼±ºè¹HºÕ»’¾mÂAÈOÑ·ÜÏìÀý ; Ð-Y8M?DÁHÂK€MåMùL´J5GƒBÖ< 4¡(qÍ?õ-ä¡Õ„ËÕÃ#¿“»1¹ ¸¸[¹·»¿VÃÆÉmÒÐÜtê øh{¸%Ü+ 0Ü2N4i4B31Â-È)N$[ô9/ýüøö]ôáóˆô6öÄøñûÿGñ; æ ·…%Œ ¨ Gûônì’äÊ܆ÖÖÑëÍçÊÿÈ[ÈÉ)˰ΦӠÚüäñBþ! R¦'d1˜9?/CWFbHGIêHXGD…@1;¬2«'Î?lô©âàÓÓÈ`Áò»›·r´—²²â²µb¸è¼l€ÊlÕ„ä¢õ§#*&}0¶8ð=WA¬CÉDÊD¥C{Aa>ÿ93+­!_@ ¤ýåòHéáËÚÁÖÔ‘ÓÆÓÕx× Ûéßånë>ñ¶ö û²ÿÒÚÊŽCÿõþLûD÷"ó/ï¨ë×èòæ)æªæèýëàð#÷sþ2ë €( .ë2¿6&9Q:q:f9%73³-¢&O9Rö¥èÂÛ_Ò²ÊíÄ1Á¦¾½”¼!½Â¾^ÁCÅLË5ÓEÝÀê´ø®U4?W?„>Î<µ9"5/(\me£ýfóê¶á÷ÚPÖ{ÓÁÑÑrÑÀÒöÔ.ØzÜ%âIè…îÂôµú1)^ Î bíýSXA ü ¡^K‡%?ÿÉþÓþRÿ7…Ú¥z ‡ Ž 8 Z  ¤ ³NwAýâù•ökóŒð îìŠê¦éhéÌéÙê|ì³îdñuôØ÷`ûþþ…í â D{:y#Q \f , ÖpÙÓþýûPúpùíø½øÙø<ùÕù˜úzûdüRý/þóþœÿ E2÷ÿ¹ÿ—ÿŸÿÊÿöÿ üÿíÿìÿöÿ   !"!"!%!%$%&#("'&$(#("* )#%$&!' %""$$"             ÿÿýÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿþÿûÿüÿÿÿÿÿÿÿþÿþÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿþÿþÿüÿûÿûÿþÿþÿþÿÿÿýÿþÿýÿþÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿþÿýÿþÿÿÿýÿüÿþÿÿÿþÿþÿÿÿÿÿýÿÿÿÿÿÿÿÿÿþÿýÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿþÿÿÿÿÿþÿÿÿþÿüÿýÿÿÿÿÿþÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿýÿýÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿþÿýÿüÿýÿÿÿþÿþÿþÿÿÿÿÿÿÿþÿÿÿýÿþÿþÿÿÿþÿüÿþÿÿÿÿÿþÿýÿüÿþÿýÿÿÿÿÿÿÿýÿÿÿýÿÿÿýÿûÿþÿÿÿþÿýÿüÿýÿúÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿüÿüÿþÿþÿþÿþÿþÿþÿýÿüÿüÿüÿýÿÿÿÿÿÿÿþÿýÿþÿþÿýÿþÿüÿûÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿþÿýÿþÿÿÿþÿþÿÿÿþÿþÿÿÿüÿýÿþÿýÿÿÿÿÿýÿÿÿýÿýÿýÿþÿÿÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿûÿýÿþÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿþÿÿÿþÿþÿÿÿÿÿüÿüÿþÿþÿÿÿþÿýÿþÿÿÿýÿýÿþÿþÿÿÿÿÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿüÿüÿýÿÿÿÿÿÿÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿþÿýÿþÿýÿÿÿÿÿÿÿýÿüÿþÿÿÿþÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿÿÿüÿûÿýÿþÿþÿÿÿÿÿÿÿýÿþÿþÿýÿýÿÿÿþÿÿÿýÿýÿÿÿþÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿÿÿýÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿýÿþÿýÿýÿÿÿÿÿÿÿþÿûÿüÿþÿÿÿþÿÿÿýÿýÿþÿýÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿþÿþÿýÿýÿýÿýÿýÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿýÿþÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿþÿýÿýÿÿÿÿÿüÿýÿþÿþÿÿÿþÿÿÿþÿüÿüÿýÿþÿýÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿûÿýÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿûÿüÿýÿþÿÿÿÿÿÿÿþÿþÿþÿÿÿÿÿþÿüÿýÿÿÿþÿÿÿýÿÿÿþÿÿÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿþÿýÿÿÿþÿüÿÿÿþÿÿÿþÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿûÿùÿûÿþÿþÿþÿÿÿÿÿþÿÿÿÿÿþÿüÿýÿýÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿýÿýÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿûÿüÿþÿÿÿÿÿþÿþÿÿÿýÿþÿþÿþÿýÿÿÿÿÿüÿûÿýÿþÿüÿûÿþÿþÿýÿþÿþÿþÿþÿÿÿÿÿýÿþÿþÿÿÿþÿÿÿþÿýÿýÿýÿþÿüÿüÿþÿÿÿýÿþÿþÿÿÿÿÿþÿýÿýÿüÿûÿüÿþÿþÿýÿþÿÿÿþÿþÿûÿþÿýÿÿÿÿÿþÿýÿûÿþÿýÿþÿÿÿþÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿüÿûÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿþÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿýÿÿÿÿÿýÿÿÿÿÿþÿýÿÿÿþÿüÿûÿýÿþÿýÿýÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿþÿýÿýÿýÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿÿÿþÿýÿÿÿþÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿþÿÿÿþÿýÿüÿþÿÿÿþÿþÿüÿþÿýÿüÿýÿþÿÿÿÿÿýÿýÿÿÿÿÿþÿýÿÿÿÿÿþÿþÿýÿüÿüÿýÿýÿýÿþÿþÿýÿýÿþÿÿÿþÿÿÿýÿÿÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿûÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿþÿüÿúÿüÿþÿþÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿþÿûÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿýÿÿÿþÿýÿþÿÿÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿüÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿþÿÿÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿÿÿýÿüÿþÿÿÿÿÿþÿþÿÿÿþÿÿÿþÿüÿûÿþÿÿÿûÿþÿÿÿýÿþÿþÿþÿýÿùÿûÿþÿýÿþÿÿÿÿÿýÿüÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿþÿüÿúÿüÿüÿüÿÿÿÿÿþÿþÿÿÿÿÿýÿýÿýÿþÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿÿÿýÿþÿýÿþÿÿÿýÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿýÿÿÿþÿÿÿÿÿÿÿþÿýÿÿÿýÿÿÿÿÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿýÿþÿþÿýÿÿÿýÿþÿÿÿÿÿÿÿÿÿþÿÿÿüÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿüÿûÿþÿÿÿýÿüÿþÿþÿüÿüÿþÿÿÿÿÿýÿþÿþÿÿÿýÿÿÿýÿýÿþÿüÿýÿÿÿþÿÿÿÿÿüÿýÿÿÿüÿþÿþÿýÿüÿüÿÿÿÿÿÿÿþÿûÿûÿüÿýÿÿÿþÿÿÿþÿýÿþÿÿÿÿÿþÿþÿþÿûÿúÿýÿýÿýÿüÿûÿûÿüÿÿÿþÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿüÿþÿüÿüÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿýÿýÿýÿþÿÿÿÿÿýÿþÿýÿýÿýÿþÿÿÿþÿþÿüÿüÿýÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿþÿÿÿþÿþÿÿÿýÿüÿÿÿÿÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿüÿúÿúÿüÿÿÿþÿþÿýÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿþÿÿÿþÿÿÿÿÿÿÿÿÿýÿüÿÿÿÿÿÿÿþÿýÿÿÿþÿüÿüÿþÿþÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿþÿüÿûÿûÿþÿýÿþÿÿÿþÿÿÿýÿþÿÿÿþÿþÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿÿýÿüÿþÿÿÿýÿýÿþÿÿÿÿÿýÿÿÿþÿþÿÿÿþÿþÿþÿÿÿÿÿþÿÿÿýÿüÿþÿþÿÿÿÿÿÿÿÿÿýÿÿÿþÿûÿýÿÿÿþÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿýÿÿÿþÿûÿýÿýÿüÿþÿýÿüÿýÿÿÿýÿüÿÿÿÿÿÿÿýÿýÿýÿÿÿÿÿþÿÿÿüÿýÿÿÿþÿüÿþÿÿÿþÿûÿÿÿþÿýÿþÿþÿþÿÿÿýÿýÿþÿÿÿþÿþÿÿÿÿÿþÿþÿÿÿýÿüÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿýÿúÿüÿþÿÿÿÿÿÿÿþÿýÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿýÿûÿúÿýÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿýÿüÿüÿüÿüÿýÿþÿÿÿÿÿÿÿÿÿÿÿüÿþÿÿÿþÿýÿýÿýÿþÿúÿúÿýÿÿÿþÿýÿþÿÿÿþÿÿÿþÿÿÿÿÿþÿýÿÿÿüÿÿÿÿÿüÿýÿþÿýÿþÿÿÿÿÿþÿýÿýÿþÿÿÿþÿýÿùÿøÿýÿþÿûÿüÿþÿÿÿÿÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿþÿþÿÿÿÿÿþÿþÿþÿÿÿþÿÿÿþÿþÿÿÿýÿüÿÿÿÿÿÿÿýÿþÿÿÿÿÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿÿÿþÿýÿþÿÿÿþÿÿÿþÿüÿûÿÿÿÿÿþÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿþÿýÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿüÿÿÿþÿþÿþÿþÿýÿüÿþÿÿÿÿÿÿÿÿÿýÿþÿûÿúÿüÿÿÿþÿþÿþÿþÿþÿÿÿÿÿÿÿþÿþÿÿÿþÿþÿÿÿþÿþÿýÿýÿÿÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿýÿþÿûÿýÿÿÿÿÿþÿÿÿþÿýÿÿÿþÿþÿþÿþÿþÿþÿüÿýÿÿÿÿÿþÿýÿýÿÿÿÿÿþÿýÿýÿÿÿþÿýÿþÿÿÿþÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿþÿüÿýÿþÿþÿúÿüÿÿÿýÿüÿýÿþÿÿÿþÿýÿýÿýÿÿÿÿÿþÿüÿûÿûÿýÿþÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿþÿûÿýÿÿÿýÿýÿÿÿýÿüÿÿÿÿÿÿÿÿÿûÿüÿþÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿüÿýÿýÿýÿÿÿÿÿÿÿþÿüÿýÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿþÿûÿüÿÿÿÿÿÿÿÿÿÿÿþÿûÿþÿýÿþÿÿÿýÿüÿþÿÿÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿþÿþÿþÿþÿþÿÿÿþÿÿÿüÿýÿþÿÿÿþÿþÿÿÿþÿüÿýÿþÿÿÿþÿþÿþÿüÿýÿüÿûÿýÿÿÿþÿÿÿÿÿþÿýÿÿÿþÿýÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿÿþÿûÿüÿÿÿýÿýÿþÿþÿþÿÿÿÿÿÿÿÿÿýÿýÿþÿÿÿÿÿÿÿþÿÿÿÿÿþÿýÿþÿýÿüÿþÿþÿÿÿÿÿýÿþÿÿÿýÿýÿÿÿýÿýÿþÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýÿûÿýÿþÿÿÿþÿýÿþÿÿÿÿÿÿÿÿÿÿÿýÿþÿýÿþÿÿÿÿÿÿÿýÿþÿÿÿþÿþÿÿÿþÿþÿþÿþÿÿÿÿÿþÿþÿþÿþÿÿÿÿÿþÿýÿÿÿþÿýÿýÿùÿùÿüÿÿÿþÿÿÿÿÿýÿþÿÿÿÿÿýÿÿÿÿÿûÿüÿüÿüÿþÿÿÿþÿþÿþÿýÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿýÿÿÿýÿýÿÿÿÿÿÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿ2_–á<©!¨+³(×ûó·Bš°–FÎþ9ýûÐùøˆöõäóøòZòò?òÌò½ó õÀö´øóúZýØÿ`Ð(>  ˆ š J„ZÇ Ù ž ' „Ïz ÎåÿKÿÿÿÿ,*Pi`rYÖÕtýú%öèñmíùè¥äOáºÞÇÜ|ÛãÚ!ÛHÜVÞ–áŸæ–íµõÁþÒö–$6+È/U3A6s8Å9.:˜9þ7`5Æ1-%^š ÷üåìˆÞ%Ô?Í_ÇLÂ+¾*»ººº´»¿ŸÃGÉÎÏÙnæÄø6 ‚)£1û7h=¼A×DòEíEðEvDAA=Ó7ñ1á*l ”Ìóñå?ÜýÔ…ÐŽÍŽË‹ÊtÊ>ËÎÌÏÎÑœÕâÚBàùæ'î›ô%ú“þÌ×­tIjÿ„üúè÷möÓõSöø%ûœÿ]_ bØÈ#O* /ô2Y69;.<8< ;ß8i5Ó0o* Kþ¹êÚ`ÏÿÆ6¿ºººººººººµºâÂ1Ì Øì±´â.9`CðEîEñEíEñEíEðEðEîEïEðE÷<³2L%Žkö[ßðЊÇF¿ ººººººººº­½ŒÄÌGÔTàñÏ8í'.¬1E4á5„6I6B5•3i1Ø.Ÿ+~'#Åo¨Í× Â ` ‘ Ï _ ™ 1  Ô “iüŽõ íÙäƒÝ¸ÖBÑÍɧÅÖÂËÀ´¿¿¬ÀãÂGÆÛÊ}Ð ÙÌå;ø´ ‚,|5®=*EíEòEìEòEíEïEñEíEðE‘C%;¯1¼$—Æö[ß…ÐvÆK½ººººººº ººº·»IĠ͉ÙDìϦ‚(22§9î?EðEîEðEîEïEðE¶C?×94.T%ð£ 'Èõ­ëSãßÝýÙ&×`ÕÔgÔ½ÔgÕxÖÇ×ÙUÚaÛ&ÜªÜØÜÏ܉Ü.ÜÒÛ•ÛœÛÜݲÞAáCåDë›ò/ûï¯<Z$W, 207ð; @CòEìEñEíEEEôAm=´7ë0€'ÁdAï~ÜüÏ Ç¶¾ºººººººººº¼£ÄÎÎÚAïn¡á-v7.@îEïEðEïEîEðEïEîEñEîEvCí;±3_*öFõãýÖ'ÏkɱÄÁ~¾½ž¼3½­¾ÁíÃyÇZË’ÏGÔ³Ú}áìésò>úAuß ‰ýä / è!¯#%…'ž)€+F-Ô.*0e1^23U3&3a21ð.Â+²&" R ¢üPî^àÚÕ‚ÎÈ2Âݼºººº ººººª¾-ÅÁÌúÕå¿úñ;$¶0Ù97BñEíEòEëEóEíEðEðEíEñEÓD¥<’3›(ÉïÿPéØ}ÍGžººººººººº)½QÃÊ<ÑMÛÙè)ù½Xw"’*°/b3D6R8¤97:!:}9M8½6Ó4ª2\0î-ä*9'm#·]B- åŽü7ö ð•éã¹Ý°Ø÷ÓcÐ0Í=Ê„Ç;Å_Ã%ÂÁ¾Á¢ÄjÇË©ÏÅÕ[ßCí®ýÝ ‰+¨3é:–AðEîEïEðEîEñEíEñEîE8E^>q6¯-ßà Gô>ßuÑVÈö¿ºººººººººº?º¢ÁÍɪÒàëó|-Ê)R29ú>ºCñEîEðEîEðEïE AWDòEîEîEñE[DCA=å7Á1*Ðÿ ØøOåëÖfÍwÅ0¾ºººº ººººººI¾öÅ‚ÎÏÙ‡ëa+Ì'L2y:ÆAðEîEïEñEìEóEëEòEíEÉE¥?Î8f1-(ý$ È÷1çþÚ-Ò­ÌûÇ*Ä?Á9¿¾Ö½_¾¦¿‘Á ÄÇWÊÎËÑâÖÝîãì&õrýd B%s Ä$Û(8,Ù.1ý2Æ4I67u899¿8Ü7e6U4¤1Z.a)]"• <ÿ:ñ%ãžØ€ÐmʮĎ¿»ºººººººu¼ÀÁÈ;Ï Ù÷çÜû:"ˆ.Ê6^>!EìEòEíEðEïEïEïEïEïEÅC×<5,X û÷wäÈÖÎÇûÀ컺ºººººº+¼±ÀÚŌ˘Ñ-ÚÚäóÀß é"Ô)ˆ.Î1o4‚6õ7â8B9.9¥8º7y6ã43ü0µ.Ö+(¶#õ³P  Xù×ð èGà/Ú{ÔRÐÀ̄ɎÆÄ²Àï¿ò¿±ÀG®ÄëÇõËËа×xá³ïÿÉq¯*T2é8í>/DïEðEîEðEîEñEìEóE-B9—:ç5t0.)rìþþìòÝ"ÓÌÅ÷¿%»ººººººº½f†ÈeÏvØžå÷‰ %–';0Š6<«@JDîEñEìEóEìE‘Cù?¥;¤6$1*)!Åâpù˜ìWážÙzÓ‰ÏwÌÊSÈ8ÇÃÆÚÆ†Ç¨È@Ê3Ì}ÎÑ0ÔYØÝOâøè+ðl÷™þÁÈ ÄŒ ˆ$¿(H,ð. 1þ2›4Ð5¨67ç6F65G3æ0ó-g)#=$6Ê÷ë|ß¾ÖNÐOËÆÆÜ¨¿@½À»*»•»ù¼`¿¹ÂúÆÌÜÑÊÚáæ ÷{îÆ$6.z4 :Ý>½B§EðEîEðEïEâCd@ÿ;Î6ÿ0Ä)L¬'íñã~ÙãÑùÌÆÈiÅßÂ7ÁrÀ‡ÀqÁÃ…Å€È ÌÿÏÊÔ•ÛCãcí¦÷û ̶l!Ò%£)H,8.w/R0Ø01å0z0É/Ú.¢-â+Æ)å&·#/ ´Üw° úzò¡ê%ãBÝØÓTТÍXËyÉÈTÇ)Ç£ÇÑÈ«Ê<ÍsÐ×ÔƒÛËãïEüZ ™Û!…*~0F5…9=Â?œAƒBwBpAt?<Ê8:4/}'Z!ñäâÓØKÑ&̼ÇÄRÁ¿˜¾¯¾²¿œÁ`ÄàÇÌÇÐ%רßëÑ÷N[™#ô)V.G1›3<5=6’6L6s54A2û/[-³)þ$ ñ²ˆ Ùýu÷hñÆëŠæBâçÞ*ٖܺ×ÇÕŒÔÓñÒ‹ÒƒÒ½ÒhÓcÔÐÕØåÚIÞ€âdèeï÷.ÿ°}dÌ ¾&ï+›/Œ25÷6D8ú8î828³6{4Ž1÷-j(!Ä þ3ñ†äG۾ӾΓÊ#ÇcăÂ|Á]Á*ÂÕÃcưɹÍaÒˆÙ|âíîü2 ÷´ |(J.!2U5º7h9>:N:™9!86@30å+&K>E qùðÊçámÜ—ØÕ™Ó5ÒšÑ]Ñ•ÑÒ7Ó¨Ô•ÖÙáÛ×ÞTâ~æOë1ð"õúÿüêÌ Ÿ]ωv"9%¶'è)v+˜,d-»- --à+8*j'ó#ÒúY 7ø§îPå Þ ØÓ½ÏÍÖÊIÉcÈ4ÈÀÈÊ Ì¶ÎÒ1×Þç|ò`þZ 1d Ï'µ-‡1³4/7ê8Ø9ü9I9Ô7œ5¶26/‚*ª#•–\:úzï@åâÝ Ø“Ó®ÐÎ@Í{Ì_ÌßÌïÍŠÏ—ÑŒÔØXݺâÈéBñ­øÒÿ˜ñ ¶í<{Á!†#à$Í%S&‚&U&ß%#%!$é"t!Ê•ÐC_@ Ê.þ ù¾ó]îõè×ã±ßKÜ5ÙoÖwÔÓÒ»ÑÐÑrÒÈÓ»ÕðØÝܺážèßð¼ùêc ÊZ£$:*&.Ü0 3—4}5°5.5ý32”/,è&‡ ×S €¦÷þìãÜÖöÑ.ÏÍËßÊÒÊzËÊÌÀÎAÑÎÔäÙÈß’çÚð0úY7 …N!b%³(+,R-‡-'-?,Ù*¾(&è"‡6ô>  Rüá÷¿óÿïŽìéÄæsä¼â>áàAߨÞ>ÞÞÞhÞûÞÒßáãâå<èáëÿï™ô ùÿ¹¦ ²½bÞ |$Ã'{*F,-2.C.Þ-­,á*ð'$$—  _hÿ6öíZäÞÝ‹Ø:ÔCÑFÏ×ÍÍðÌ|Í«ÎÐÓóÖ5Üiâóêrôþµ ó¾ Ö%7*-÷.0¦0’0ñ/À.Ù,***&¸!J0¦ Âþµ÷ñë´åµáØÞÀÜFÛUÚúÙÚ¼ÚÁÛ0ÝåÞüà›ã³æ4êÉídñõøü~ÿÌ . B 2Ñnî ÉQm @!Æ!ù!Ò!@!F ²nWT¼’ õõÿ¯ù<óÎìxæ4á'Ý´Ù¸Ö¨ÔHÓ…ÒZÒÞÒÔÒÕÚØ™Ü'áçaï®÷;ëz·B %`)Y,e.‘/)0'0‰/Y.J,J)%< ϵV âøŠðýè’âùÝcÚ×yÕ_ÔòÓÔÜÔ;Ö~ØIÛ‹Þ†â¤ç{íjóPùÿ€ Fl uÅãn®­vÜþýÙ”6º $ o ®¯þûLøñô¤ñ@îÿêÌçÑä‡â‚àßÞPÝÝFÝÞ<ßáßã¥çZìœñi÷™ý¦ 9©N˜! %÷'B*‡+9,B,­+v*7(0%!°)¬âáþÛö ï‘çeáíÜ?ÙBÖ_Ô@ÓÄÒüÒÕÓWÕÕ×ÛóÞÔã\êjñ¯øåÿñ« é“î!\#ü$&]& &Q%ú#("÷÷Už ³ZNÿlûæ÷¯ô×ñ^ï@í€ëêõèè‘ç:ç!ç7ççøç›èté}ê»ë9íðîêð2ó±õø–ûóþu2 ö Þ«Nbྠ" ##d#Ì"‘!Õc¡?e #±üöïWé¬ãdß#ÜlÙ`×ùÕrÕˆÕ_ÖØhÚmÝ7ánæúìøó7û‡Ì Çaü!.$¢&^(b)©)0) (/&Ä#Æ éÒû âßÿúô„ïëçäìáeà¦ß[ߎß'àTáçâÛä|çbêtí›ðÐóùöúýÝÿˆRt j 4 ßZÁûðŸfl2£Â€ÛÓ^Š PÂçÕü—ø<ôíïµëµç/äwáfßòÝö܂ܜÜKÝÞhàLã$çìdñF÷kýÀ VG¬Å´"%Ó&å'?(é'Ó&%¬"«~âÆT ¼-üºõœïïéØä.á„ÞšÜJÛ¡ÚÚ-ÛeÜÞNàmãdçìàðãõÞúÄÿhÆ JQÕÊ8pê Õ\¬ÑØÌ³ › kbT^cþpü~ú†øœö§ôÃòâðï\íÄëYê#é0èçFçdçñç÷èzê{ìúîññYõ#ùGýš)À PºÞ‹M_ Ï!¯"#É"õ!Š `\$?á "*ûõHïÓéÕä2á~Þ‡Ü!ÛhÚSÚèÚ$ÜóÝ^àÎã\èí.óùÙþŸ/ k5iá<ûæ N!/!‡ gŽJ# Ùí ó-™ý2ú&÷lôòðŽîSí…ìýëÍëÜë*ì«ìWí)îïð;ñjò¯óõnöï÷†ù?ûýÿ 4zÐ8 þGj` nhø ›ŸþX7˜ ™D½þ úVõ´ðLì/è™äùáùß¹ÞÞÛÝCÞJßíàzãâæ@ëð\õáú9Ð d§" ±!¼""#ú"1"ä æ'kMV >)?ûŒö1òIîÞêèÏåQä‡ãBã~ã7äpåFçyéìÀî®ñ«ô±÷§ú…ý2ºîƒ Û ý â  *“ÛÿÞ™@½ N \ * Ó 2iY²ÿý]ú÷¹ôïñ;ï¸ìqê€èëæÐå/ååŸå¯ædè¨êzíÔðœôÇø9ýØŒ= ÇñL¬|‰ ÿ õ L =z*q e)èý«ø¦óíî£êÞæèãÖá`à°ß„ßèß×à}â—ä¬ç6ë ïLó“÷òû*J#« Ëx«Z‰6c"n`ý[}€d D ö 3‚þîürûúÕø®÷™ö—õ¦ôÅóðò3òñíðrððêïêï!ð™ðQñWò¤óIõ.÷mùâû¢þ~“±Ù í ß• ¥¾=4…<RÕÍIX ™ýcøÞóˆïë÷çíäÜâ_á{à8àà‡á!ãUåŠè<ìjðãôžùkþ7ÝT e4Æš°,%Œv¨N†i† ÷^ðÿ¤üùÑö[ôPòðZïoîñíÂíîí^îï÷ï ñ=ò…óáôCö¦÷ ùeúÁûý]þ¤ÿã*s½b¹ \ ¢ Ò èÜ-xy+ƒ~\ = Óíþžû@øêô­ñ¢îÞërézçúå å»äøäâåhçŒéAìvïó÷bûÏÿF¶ü ÿ¢ÐvCnüa?kÍ«. »m2ü$øUôäðàíTëUéÝçþæ®æìæ³çôè¤ê¶ìï®ñnôK÷%úùü¯ÿ3¥… ] `  – × Þ ¿ q … î D “ Ð 4]kwdG ¼ZÿÔýAü‘úÞø÷cõ¹óò±ðiïfî¢í<í$íxí-îPïÜðÒò"õÕ÷Êúþ^ÖYÁ  ·ÐÍæ^9v%IþJ Q#äþ¢ú~öŠòóî±ëúèÀæ%åEäüã;äåæ è0ë-î{ñõÈø”üOòdŒ ] ÉÅGSäû¨âÈT£µ © } Mþ÷ÿ[ýÈûfú/ù/øM÷§öö®õ\õ&õõôôóôõõGõ‹õÖõIöÊöv÷Aø6ùSúŸûý¶þlXRgyŽ ˆ f„«|çOŠ^ Î é¿_äýVúÐömó@ð[íÛêÈè;ç7æËåöåÁæ èêˆìoïÄòaö:ú4þ,ß b ŒS˜_•4F½²±ôü Ñ›X;ÿ2übùÛö™ô¿ò8ñðaïï ïhï ðøðòióÚôdöõ÷ùû¨üþyÿ°äïïÏ¢a»Xìz û r Ý - s ‘ f  … Ä È” z™‘cþü¾ùa÷õßòÜðï’ífì¥ëMëjëìíšî”ðøòºõÆøü„ÿ  @ Hë1ö;ó§£…š` ëL ý~ù+ö&órð1îYìë/êÚé ê²êÖëYí=ïmñÖónöùÒû{þw¨®Y Ï è ¼ @ } v 4 ¹  J e i dUI;66APg‰ÿ§þÄýàüøû ûú(ù7øD÷]ö~õ·ôô}óóêòôò8óÆó‘ô¯õ ÷´ø•úµüÿo÷Œ ‹ Õ ê²*7Þ¾ó®øÉG ` Cë‡ÿ ü©øbõ[òžï>íPëÖéæèxè›èEétê ì:îºð†ó˜öÉùý\˜§{ 7 jcâõœÜÃV§ ¾ ² †W#ÿ"ýoûíù¢ø’÷·öö­õrõhõyõ½õö|öíöz÷øžø4ùÔùvúûÐû‹üRý)þÿ0cŸë5‚à ò  ó ¯ 7€{1 Ÿ Z È êÌsîQþžûèøHöÉó}ñ{ïÂísìŽëë$ë¡ë¡ìîùïHòãôÔ÷ìú6þxÇñó ¨ °Óq•9YVBâ 9 s‰›Åþýûkù÷õBóáñÚð8ðòï ðzð<ñ?ò~óðô‚ö/øêù£ûYýøþ}æ1QO#ÒaÈPx…‚tV4˃(º0’Íðëˆ0ÿ³ý-ü‘úùøb÷Ýõsô1óòEñ³ðlðzðâðžñ¾ò,ôõõøWúÙüˆÿ> Ãc Ö êk:w1|I¯¨M ¦ Ä¿ Žý„ú£÷úô›ò’ðíî²íéì“ì²ìAí<î˜ïMñHó…õå÷gúóütÿã+L.Î $ . å R k D Ò / Q M . î®\Ò¦~ÿ…þ©ýßü*ü‡ûöúoú÷ùƒùùµøUøÿ÷¬÷j÷/÷ ÷ûö÷2÷÷ö÷—øeù`ú‹ûßü[þýÿ­€U/÷¬ 6 ’ ±‰CŠ V ¹ Ä zÅÿùü8úŠ÷õ»ò¸ð ï¿íâìpìvìðìÛí3ïïðódõø÷Ãú›ýyO à Ù ˆÌ²,?ð82Ó 8 ` aDóÝÿÝýþûOúÔø”÷‘öÍõJõõ÷ôõrõïõŽöI÷øïøÐù³ú“ûnüDý þÓþŠÿ:é“DëŸM¹v%Üy û 9 X F ÿ Œ ÓïÇsç2[lþkübúeøyö·ôóÆñ¯ððïƒïyïÐï…ð£ñóâôïöIùÌûtþ(≠c | ;ªªLu8‡wý7  ÒS½…þüŸùu÷ˆõëó˜ò¨ñ ñÎðîðZñ%ò&órôëõ‡÷Iù ûàü¢þOí`´ÖÉ“"Çàͨ\ ›1¯9­2§$˜tÏ*n°ÿÞþøý ýüû ú ùø)÷Tö¤õõºô‡ôœôãôpõAöM÷ø%úàûÆýÐÿä /;3 ï ½·P’kçý·  / £|âýEûËøxöbô“òñùï:ïäîôîfïBðqñõòÁôÅö÷øEû¢ýûÿDouAÑ   Æ " 6 ý { Ä Ë ° j ¡-¼[Òþ°ý±üÐûûvú÷ùšùPù"ùùùøüøùù0ùUùwù¨ùÛù úiúÍú:ûÄû`üýçýØþÖÿíR˜ÛI` X & Å ( O 4 Ë $ , ó{ÃâÒ±ÿ~ýAûù ÷+õ|óòõð,ðÃï¶ïðÂðÝñDóõ÷4ù–û þt´Æ —  N$·qÓÝ Ÿ  ^ }qfGEÿLývûÏùXø÷"öeõïô·ô¿ôõvõöæöÓ÷Óøãùýúü)ý2þ+ÿã©Uïzò^Àk±ý;}³ã&í =³7:+í¦ÿCþÊüXûÜùzø!÷õõëôôó#óóPóÝó®ôÑõ3÷Ùø°ú¸üßþP¤” b Þ %ŸÎ§6 u ª §r*Ê|þ-üúø:ö·ôxó‘òúñ»ñÔñ>ò÷òøó3õªö@øþùÅû—ýcÿ¹6޲¨eñA f W  ÄD¯NŽÍP“ê@£…ÿþþvþñýkýæüYüÒûBû¶ú+ú¤ù(ù·øZøøå÷Ú÷ó÷5ø£ø;ùú÷úü]ýËþCÜy®5 Î Í •  S @ Ý ) ' á R–|Jþßû¿ù»÷ëõOôóóñMñëðöðOñòó^ôÿõÉ÷Æùåû þ7ZeP† ¼ µ _ · Î  P S . Ùpîhágÿ·ý…ü|û—úÝùIùäøø‚øƒøŸøØøùxùÛùBú¶ú!û˜ûüzüéü^ýÒýQþÍþ]ÿìÿ†/â£i2ÈŒ>ÝbÈ  ÿ­-s‡k¬rÿ¶ýõûAú˜ø÷´õˆô—óïò‹òzò¸òEó(ôNõÀöiøHúNüoþ’ÅÚæ¶` ½ Ý ¥ > ~ ª ‚ ' ‡ÈÞêèüþýOû«ùBø÷öUõëô²ôÈôõ™õQö4÷:ø[ùŽúÈûý?þiÿ~|i2äréA…«ËËμ¨ŽkKö¿ˆ>ð‹—ýQÀÿÜþãýëüâûäúæùùø!øf÷Íö^ö!ööEö­öM÷3ø>ù’úýû ýUÿí»y!™ ç ÷ Ä J d û ? 7 ì bž»­œ†þuü€ú¦ø÷—õrôóó¸òÎò%óÒó¿ôëõN÷×øƒúDü þÓÿ„%¥ý&Ø[ § » › J Ï/oœ±ÄÌßî=ŒÿÙþBþ¶ýAýÙü~ü3üêû°ûxûEûûéú¿úŸú}úmúaúgú~úªúêúLû¿ûYü ýÜýÅþÌÿÙ1b®¸¤l  n œ C · ìç¨5 ß9þ^üú×ø@÷Þõ±ôÇó%óÍòÅòó¥óˆô±õ÷µøwúaüYþQO1üœ 7 Ê ' :  Š Ð Û ³eôráRÓÿ]þýÆû¶úÉùù~ø$øñ÷é÷øMø³ø-ù¾ùYúû¬ûYüý¤ýCþÒþaÿÜÿTÁ1šiÐ;¢yçG¦ö8h~{Vªl’œƒUÿÄýjüûÏù™ø…÷’öÑõDõðôÞô õ{õ0ö!÷Qø²ùEûøüËþŸZÀ5 v z 8 ¬ Õ ¬ ; { | ; È&i´×þýUûÊùbø4÷Aö‹õõêôõôIõÑõ‘ö~÷øÁù ûXü°ýüþ<h‚wQ“ýCkp^3ó§M퇹Oî†&Â`÷Ž«ÿ$ÿ¡þþuýÐü1üûîú]úÎù]ùúø·ø•ø–øÀøù•ùBúûü9ý}þÙÿ9´"’æ 4  É > s `  t › 2± Dp–þÄüúúSùÓ÷‚önõšô ôÇóËóô²ô‡õ¡öç÷`ùôú¢ü]þ ¿VÔ)QF ‡ Î à ´ Y Í>QA8 ô ÿ?þxýÚüMüáû‹ûNû%ûû ûû'û?û_û„û¨ûÓûþû.ü`üšüÜü%ý~ýâýTþÛþiÿ »}Hí½ˆ@íté,O@’ô!#þ¯IÒÿIþ»ü<ûÁùsø8÷:öfõØôôyô«ô,õèõëöøùûÒü—þe-ô•r‘ x  y “ d ô F Y Bö‘‚õmÿúý’üWû9úKùŽøý÷¥÷z÷‚÷µ÷ø’ø/ùçù¯ú‚û^ü6ýþÙþ›ÿDçvña¹ I¯Õø2Mau††pW&ß“ò;o—ÿ¨þ°ý±ü³û¾úÒùùEø´÷C÷÷óö÷r÷øÈøÁùâú5üœý(ÿ³Mèhß F ) à H y [ ü \ u ] ’øF‡Ôþý‚ûú©ø†÷“öãõmõ;õHõ”õöØöÉ÷Þøúfû¾ü$þ€ÿÎ 48ÔfÊÚ'§„êJ®…ú~£ÿ;ÿÞþ‰þ/þåýýBýðüžüMüüû­ûdû#ûæúÁú¢ú¡ú±úßú'ûûü¼üý]þUÿYq”¶Õåá¾{ n — “ H Ó0ÌbÙA¦þýsûöù™øi÷iö õõÏôÐôõ”õUöT÷€øáùYûóü•þ4ØbÚ(MCþ… Ë Þ ­ S ºýøÏmE4ÿ,þDýsüÄû7ûÊú~úTúEúRúuú­úòúJû¢ûüjüÌü4ýŽýõýHþ¨þûþUÿ¯ÿeË7ª%ž'¤*¨ˆÙKPD¯-‰¾ÕÍ­ÿFþÿüÆûútùrø”÷åöaöö ö1öœö9÷ø#ù]úÁû@ýÖþq©1’Öã¿ \ ½ Ù · R ® ØÆ’3Â;³1ÿ»ýXüûùùùGø­÷[÷-÷@÷y÷é÷uø0ùþùåúÝûÕüÙýÎþÁÿ—e»B­>cywrU<ëÁ‘a5üÌM ³Zòynÿ×þ/þ…ýÒü$ütûÒú;ú¹ùNùùÕøÌøñø6ù²ùLúûüýGþ‡ÿÙ,ˆÔ.'÷• û (  É ; {yVüŒþfÏþ<ý±ûPúÿøí÷÷RöÝõ¨õ­õ÷õvö-÷ø)ù]ú¯û ývþÜÿ/~©½¥iüfœ¬‹IÞZ¹G{´é&pÊÿ1ÿ¦þ-þÆýmý(ýêüÁü˜ü€üeüWüEü=ü/ü+ü&ü%ü0ü;üXü{ü²üôüQý·ý:þÊþrÿ!é·‘m@Ð~|Ïëç­F°íýï´l §þ>ýÜû‹úVùBø[÷¡ö$öÚõÓõözö%÷ øùbú½û>ýÆþQß\Æ -Ùb ª ¼ • 0  Ûð㽄DËÿ£þ„ýŽü«ûòú_úëùªù„ùˆù¬ùêùHú·ú6ûÇûUüòü…ýþ¥þ2ÿ¥ÿ{Û2~É OŠÍ H‡Âÿ0c„Ÿ¦ž}Kûm¾ë#ÿ,þ+ý0ü8ûUú€ùÎø:øÌ÷’÷}÷¤÷ö÷€ø9ùú3û`ü¸ýÿˆûjË:2 – û   £  GO)Û|ý† ÿšý:ü÷úÚùâø øŒ÷/÷ ÷÷X÷Ì÷eø-ù ú ûü,ýJþ[ÿfYF ÀMÁDVS6Àp¶PèŠËg¾rÖÿ„ÿ-ÿ×þwþþ±ýBýÙülüþû û<ûôú­ú†úoútú˜úÙú:û¾û`üýþíþûÿ$>U]P#Ü^¿èØ  |—h´AÎþVýïû™újùYø|÷Ñö[ö'ö#öhöÛö‹÷møqù¦úëûKý³þrÆùËkÐ í¢#ŒÑ!7E\q£ÿÖþ#þƒýûüŽü3üûûËû¼û·ûÂûÞûýû)üWü‰ü½üðü(ý[ý“ýÌýþKþŒþàþ3ÿ™ÿþÿsó}£AÒjíiÑUf^(ÕV´ò ðÏÿ›þfý1üûúù?ø™÷%÷àöÔö÷_÷û÷Çø½ùæú%ü‰ýõþiÞK¦Üùâž& o ‰ `  u¯É¶ŒNµrÿ6þýüûTú³ùCùùøÝøçøùpùçùtúûÍû‰üMýþÊþ†ÿ ÅHÇ-„Ï1Net|„‚xwcY<ð´o­5§nÿºþÿý>ý~üÃûûqúâùuùùïøàøùJù¹ùZúûü ý2þhÿ§î5p•¡‰DÙ, V = õl·Í¹„1Ê]ïþˆý0üòúÕùßøø€÷)÷øö ÷I÷¿÷`ø+ùú"û@üjýšþÄÿâñîÊ&¢ñ#)Ý‘)±)u×QÅIÝÿqÿÿ¾þyþ0þöý½ý‰ýVý%ýóüÆü”üjü<üüùûåûÛûáûóû üXü²üýý5þáþ¥ÿjI+ ñÄ‹=ÎE¶©ty¾ÒÍŸdÅþoý$üìúÊùÒøý÷W÷êö«ö«öãöM÷õ÷ÆøÅùêú*üýãþB õ-KC±\b;ä_¹ëûñïÿýþþGý•üûû„û*ûîúÐúÏúâúûMû ûöûXüÁü&ýýõýUþ¶þ ÿ`ÿ³ÿùÿEŠÖ&oÉvÍ-…ß0x·àþþí¼p €ã#Ti~ÿ{þ{ýxüû›úÉùù‡øøâ÷Ó÷ø÷LøÔø‡ùiúoû—üØý,ÿ‚ß9y®² NÜ# D  Ì9‚—^Ïy1ÿêý¸ü û«úÖù7ùµørøNøeøøù‰ù3úïúÅû£üŠýtþTÿ)ñ­OßR±ô"<@6øÊ–`%ë°u:Å…HûµZ¢ÿ5ÿÀþ?þÀý9ý²ü1ü°ûBûÝúúUú2ú3úPúúóúuûüßüÅý¶þÇÿÑõ #%æ‹d‰|6ÀAG"æ“7Ùþ€ý2üøúçùìø.ø÷2÷÷÷K÷Ã÷bø2ù&ú5ûaü”ý×þ Bcra2Ù[²áãÅyüN—ÙY¡üÿXÿÍþHþßýý5ýÿüÎü¶üü˜ü’ü–üœü¥ü±ü¾üÌüàüòüý-ýXýˆýÉýþnþÐþLÿËÿZôGõ¢DáfÜ5oŒ}RózÑ "àÿ±þ~ýSü6û/úGù€øé÷w÷B÷:÷i÷Ï÷eø-ùú5ûjüµýÿgÂLmf:ÝQšsÞíã‰ÿxþzý–üËû'û ú?úúéùûùújúÀú:ûµûJüÙütý þœþ+ÿ­ÿŒðC”Ò Dm›Âæ/RuŒ­µÅ¾®]ÀPÍ:‹àÿÿLþyý«üÝû$ûsúâùfùùÛøÔøñø=ùµùRúûüý3þkÿ¡ç#WnqIûÌêÊòI[_,ùQûþ³ýwüXûWú~ùÏøOøý÷ã÷ð÷6ø¡ø8ùïùÅú²û­üµý»þ¿ÿ³r/ÒR¾ý,4&Æx"½Réy ¨Aæ;õÿ«ÿdÿ ÿÚþ–þMþþ¹ýkýýÌü„ü6üùû¼û”ûuûkûwû–ûÖû(ü›ü$ýÈý‚þUÿ%÷âÀDÛMœ¸±o n¯Ä·“T Ãþxý9ü ûþù ùLø³÷O÷!÷%÷c÷Ò÷søBù6úLûxü¾ýÿL†ÁÙܶn÷Wƒ‹\“üH~¢ÁÖôLÿ…þÞýAýÅü^üüÚû¼û°û¼ûÒûúû(ücüœüãüýfý£ýæý$þcþ£þßþ)ÿfÿ½ÿþÿ_¹#zôjÞI§ú2_fY*ØpÜ3k‡—™ÿþ€ýwüxûú¼ùù{øøß÷Ó÷ÿ÷ZøæøŸù…úˆû³üïý<ÿ‹Ý)^~yMøi²»˜=®ýÔže5ÿþøüü!ûnúØùtù0ùù-ùhùÀù7úÌúlû)üáü©ýkþ'ÿáÿ}¢}Î ;\muth`H:  ðÙ·˜o= Áx³>Ãÿ6ÿ¤þþjýÆü-üœûû¢úAúýùÒùÉùÞùúsúîúûEüýþ÷þýÿúûèÀz’å çyÁè ÿ þAýzüÊû>ûÎú†ú`ú\ú€ú¾ú!û˜û*üÊüzý1þêþ¤ÿM÷‘”ñAx•¥›ƒZ&âžMÿª^ Æ~@Ûÿ¯ÿ„ÿfÿCÿ)ÿÿ÷þæþÎþ¼þ¨þ—þ„þzþfþdþUþ\þYþhþvþþ­þÑþÿþ2ÿjÿ§ÿéÿ#iªé'[¯ÑßìæØÃžsD͆FÆÿ‹ÿKÿÿêþÈþ§þ”þþ…þzþ‘þ–þ±þÉþåþÿ&ÿKÿkÿÿ­ÿÌÿåÿ '4GS`luU?þÿkismet-2013-03-R1b/timetracker.h0000664000175000017500000000533012124602454016137 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TIMETRACKER_H__ #define __TIMETRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include "globalregistry.h" #define TIMEEVENT_PARMS Timetracker::timer_event *evt, void *parm, \ GlobalRegistry *globalreg class Timetracker { public: struct timer_event { int timer_id; // Time it was scheduled struct timeval schedule_tm; // Explicit trigger time or number of 100000us timeslices struct timeval trigger_tm; int timeslices; // Event is rescheduled again once it expires, if it's a timesliced event int recurring; int (*callback)(timer_event *, void *, GlobalRegistry *); void *callback_parm; }; // Sort alerts by alert trigger time class SortTimerEventsTrigger { public: inline bool operator() (const Timetracker::timer_event *x, const Timetracker::timer_event *y) const { if ((x->trigger_tm.tv_sec < y->trigger_tm.tv_sec) || ((x->trigger_tm.tv_sec == y->trigger_tm.tv_sec) && (x->trigger_tm.tv_usec < y->trigger_tm.tv_usec))) return 1; return 0; } }; Timetracker(); Timetracker(GlobalRegistry *in_globalreg); virtual ~Timetracker(); // Tick and handle timers int Tick(); // Register an optionally recurring timer. Slices are 1/100th of a second, // the smallest linux can slice without getting into weird calls. int RegisterTimer(int in_timeslices, struct timeval *in_trigger, int in_recurring, int (*in_callback)(timer_event *, void *, GlobalRegistry *), void *in_parm); // Remove a timer that's going to execute int RemoveTimer(int timer_id); protected: GlobalRegistry *globalreg; int next_timer_id; map timer_map; vector sorted_timers; }; #endif kismet-2013-03-R1b/README.win320000664000175000017500000000713312124602454015300 0ustar dragorndragornKismet Win32 Readme 1. Requirements 2. Quick Start 2. Configuring Kismet 3. Building Kismet 1. Requirements The Windows version of kismet requires Windows 2000, Windows XP (32/64bit), Windows Server 2003 (32/64bit), or Vista (32bit). At this time, only two kinds of sources are supported: * Drones * The AirPcap USB capture adapter from CACE Technologies (http://www.cacetech.com/products/airpcap.htm) THE AIRPCAP ADAPTER IS THE ONLY WAY FOR KISMET TO CAPTURE LIVE 802.11 TRAFFIC UNDER WINDOWS. NO OTHER CARDS ARE SUPPORTED. THIS LIMITATION IS CAUSED BY THE LACK OF SNIFFER-MODE CAPABLE DRIVERS ON WINDOWS; THE AIRPCAP ADAPTER CIRCUMVENTS THIS LIMITATION THROUGH THE USE OF A SPECIALIZED CUSTOM DRIVER. If multiple AirPcap adapters are plugged in, Kismet is able to take advantage of them to listen on more than one channel simultaneously. 2. Quick Start The easiest way to run Kismet on Windows is downloading and running the installer executable available at http://www.cacetech.com/support/downloads.htm The installer creates an entry under "All Programs" with the following items: * Kismet: the program executable. * Kismet Configuration Console: the GUI that can be used to configure the program behavior. * Command Line Prompt: this opens a dos console in the kismet installation folder; advanced users can use this to manually run kismet_server.exe, kismet_client.exe or kismet_drone.exe. * Kismet Logs Folder: this shourtcut allows access to the files that kismet produces when it runs. The folder will be empty until Kismet is run at least once. After the installer is done, just click on "Kismet", and the program will start with all the available AirPcap adapters as sources. 2. Configuring Kismet Run the Kismet Configuration Console (start -> All Programs -> Kismet -> Kismet Configuration Console). You will have the option to configure: * the local sources Kismet will use for packet capture. * the list of drones Kismet will try to connect to for remote monitoring. * if kismet will log information about the discovered networks to disk. Additionally, you will be able to edit the kismet.conf, kismet_ui.conf and kismet_drone.conf files to tweak the program advanced settings. For a reference on these three configuration files, please refer to the program manual. 3. Building Kismet Requirements: * the Cygwin Unix emulation environment. Install it from http://www.cygwin.com/, and remember to include the development packages (gcc and make at least). * the kismet sources, from http://kismetwireless.net/download.shtml * the AirPcap developer's pack, from http://www.cacetech.com/support/downloads.htm IMPORTANT: unpack the AirPcap developer's pack INSIDE the folder with the Kismet sources. You want the AirPcap_Devpack_XXX folder to be in the same folder of the Kismet makefile. The reason is that Cygwin appears to have a bug which prevents proper linking if the devpack is not in the same directory that Kismet is compiled in. If kismet_server.exe instantly exits with no output, it is typically indicative of a linkage path problem. Instructions: a. run the following configure line: ./configure --enable-airpcap --with-airpcap-devpack= Where is the name of the AirPcap Developer's pack folder, containing WinPcap and AirPcap b. Build Kismet by typing 'make' kismet-2013-03-R1b/README.appletv0000664000175000017500000001235512124602454016013 0ustar dragorndragornTested on AppleTV that was originally set to version 1.1 and downgraded to 1.0 via Factory Restore http://manuals.info.apple.com/en/AppleTV_UserGuide.pdf The first step to getting kismet running on AppleTV is to install ssh. If you are not familiar with AppleTV mods I suggest you look at: http://wiki.awkwardtv.org/wiki/Main_Page I found it easiest to open my AppleTV and place the ATVLoader on via USB hard disk interface. First run through the AppleTV setup. I chose to reset my AppleTV before preparing for the kismet install. TV->Settings->Reset Settings->Factory Restore. (Warning this resets to 1.0) I went with a Streaming only config (not necessary) after the reset. Open up the AppleTV and attach the Hard disk via external USB case. http://wiki.awkwardtv.org/wiki/Hardware_Modification_Prerequisites On OSX the disk should mount as follows once it is plugged in. /dev/disk1s3 on /Volumes/OSBoot (local, nodev, nosuid, journaled) /dev/disk1s4 on /Volumes/Media (local, nodev, nosuid, journaled) We need to install AwkwardTV Loader so we can enable ssh. http://wiki.awkwardtv.org/wiki/ATV_Loader http://plugins.awkwardtv.org/det.php?recordID=atvloader http://alanquatermain.net/atvloader/ Unpack ATVLoader.zip to get ATVLoader.pkg, run it once it is unpacked. Choose your OSBoot partition in the installer... Umount the disks, reinstall the drive and turn on your AppleTV. Make sure you boot wit the LAN cable plugged in. Then enable ssh. TV->Awkward TV->SSH Service Disabled->Enable This make take a second because the machine needs to generate the ssh keys. Get the IP and ssh in to the AppleTV using the username frontrow with a pass of frontrow. TV->Settings->About Welcome to Darwin! MacbookPro:~ kfinisterre$ ssh -l frontrow 192.168.2.68 Password: Last login: Mon Aug 6 21:17:35 2007 -bash-2.05b$ sudo sh Password: (frontrow) sh-2.05b# Make sure you use the username frontrow and the password frontrow. Make yourself root via 'sudo sh'. (Note this is "sh" and not "su") Mount the hard disk in rm mode. sh-2.05b# mount -uw / If you check ifconfig you can see that configd is doing some nasty things to prevent both interfaces from working together. Note how en1 is inactive. If you remove the LAN cable you will note that en0 will switch to inactive. -bash-2.05b$ ifconfig ... en0: flags=8863 mtu 1500 inet6 fe80::217:f2ff:fef8:b946%en0 prefixlen 64 scopeid 0x4 inet 192.168.2.109 netmask 0xffffff00 broadcast 192.168.2.255 ether 00:17:f2:f8:b9:46 media: autoselect (100baseTX ) status: active supported media: autoselect 100baseTX 100baseTX 100baseTX 100baseTX 10baseT/UTP 10baseT/UTP 10baseT/UTP 10baseT/UTP none en1: flags=8863 mtu 1500 ether 00:19:e3:dd:cf:db media: autoselect () status: inactive supported media: autoselect wlt1: flags=41 mtu 1500 To prevent this behavior we need to disable the configd Kernel Event Manager. We first need to set a static IP address on the LAN interface. TV->Settings->Network->Configure Ethernet->Manually Connect via ssh again to your new static IP and then disable KEM and reboot. This is also a good opportunity to install kismet. -bash-2.05b$ sudo sh Password: sh-2.05b# cd /System/Library/SystemConfiguration/ sh-2.05b# mv KernelEventMonitor.bundle/ KernelEventMonitor.bundle_disabled Next set launchd to fire off kismet at reboot. sh-2.05b# cd /System/Library/LaunchDaemons/ sh-2.05b# cat > com.kismet.kismet_server Label com.kismet.kismet_server OnDemand ProgramArguments /usr/local/bin/kismet_server --daemonize ServiceIPC download and compile kismet from svn MacbookPro:~/Desktop kfinisterre$ svn co http://svn.kismetwireless.net/code/trunk kismet-devel scp it to the AppleTV MacbookPro:~/Desktop/kismet-devel kfinisterre$ scp /usr/local/bin/kismet* /usr/local/etc/kismet* frontrow@192.168.2.68:/tmp MacbookPro:~/Desktop/kismet-devel kfinisterre$ scp /usr/bin/nano frontrow@192.168.2.68:/tmp sh-2.05b# mv nano /usr/bin/ sh-2.05b# mkdir -p /usr/local/bin sh-2.05b# mkdir -p /usr/local/etc sh-2.05b# mv kismet kismet_client kismet_drone kismet_server /usr/local/bin/ sh-2.05b# mv kismet.conf kismet_drone.conf kismet_ui.conf /usr/local/etc/ Edit the kismet.conf accordingly sh-2.05b# grep frontrow /usr/local/etc/kismet.conf suiduser=frontrow source=darwin,en1,none Since the drone is broken set kismet_server up to listen on the eth0 interface set allowedhosts= and bindaddress= allowedhosts=192.168.2.0/24 bindaddress=192.168.2.68 Set the log path to /tmp also. logdefault=/tmp/Kismet Next start kismet_client -s AppleTV:2501kismet-2013-03-R1b/gpsfixed.h0000664000175000017500000000307112124602454015436 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __GPSFIXED_H__ #define __GPSFIXED_H__ #include "config.h" #ifndef HAVE_LIBGPS #include "clinetframework.h" #include "tcpclient.h" #include "kis_netframe.h" #include "packetchain.h" #include "gpscore.h" class GPSFixed : public GPSCore { public: GPSFixed(); GPSFixed(GlobalRegistry *in_globalreg); virtual ~GPSFixed(); string FetchType() { return "fixed"; } string FetchDevice() { return "virtual"; } virtual int Timer(); // Hooks so we can override straight to the TCP core virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return in_max_fd; } virtual int Poll(fd_set& in_rset, fd_set& in_wset) { return 0; } virtual int ParseData(); virtual int Shutdown(); virtual int Reconnect(); virtual void ConnectCB(int status); }; #endif #endif kismet-2013-03-R1b/text_cliframe.cc0000664000175000017500000000465312124602454016620 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "text_cliframe.h" TextCliFrame::TextCliFrame(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { netclient = NULL; next_id = 0; } TextCliFrame::~TextCliFrame() { if (globalreg != NULL) { globalreg->RemovePollableSubsys(this); } } void TextCliFrame::RegisterNetworkClient(NetworkClient *in_netc) { netclient = in_netc; netclient->RegisterClientFramework(this); } int TextCliFrame::RegisterCallback(textcli_cb in_cb, void *in_aux) { textcli_cb_s cbs; cbs.id = next_id++; cbs.cb = in_cb; cbs.auxptr = in_aux; callback_vec.push_back(cbs); return cbs.id; } void TextCliFrame::RemoveCallback(int in_id) { for (unsigned int x = 0; x < callback_vec.size(); x++) { if (callback_vec[x].id == in_id) { callback_vec.erase(callback_vec.begin() + x); return; } } } int TextCliFrame::ParseData() { int len, rlen = 0, roft = 0; char *buf; string strbuf; len = netclient->FetchReadLen(); buf = new char[len + 1]; if (netclient->ReadData(buf, len, &rlen) < 0) { _MSG("Textclient::Parsedata failed to fetch data", MSGFLAG_ERROR); return -1; } if (rlen <= 0) return 0; buf[rlen] = '\0'; // Parse without including partials, so we don't get a fragmented command // out of the buffer vector inptok = StrTokenize(buf + roft, "\n", 0); delete[] buf; // Bail on no useful data if (inptok.size() <= 0) { return 0; } for (unsigned int it = 0; it < inptok.size(); it++) { netclient->MarkRead(inptok[it].length() + 1 + roft); inptok[it] = StrPrintable(inptok[it]); for (unsigned int c = 0; c < callback_vec.size(); c++) { (*callback_vec[c].cb)(inptok[it], callback_vec[c].auxptr); } } return 1; } kismet-2013-03-R1b/darwin_control_wrapper.m0000664000175000017500000001710612124602454020422 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define __IN_OBJC_FILE__ #include "config.h" #ifdef SYS_DARWIN // Is this a bad idea, to try to merge obj-c and c++ code into one codebase? // Yes, probably. // Code derived from kismac by KF #import #include #include #include #include #include "apple80211.h" #include #include "darwin_control_wrapper.h" #import "darwin_wificontrol.h" int darwin_bcom_testmonitor() { NSDictionary *dict; NSData *fileData; NSString *error; NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; fileData = [NSData dataWithContentsOfFile:@"/System/Library/PrivateFrameworks/AppleTV.framework/Versions/Current/Resources/Info.plist"]; dict = [NSPropertyListSerialization propertyListFromData:fileData mutabilityOption:kCFPropertyListImmutable format:NULL errorDescription:&error]; if(!dict) { NSLog(@"%s", error); } else { if (strcmp([[dict valueForKeyPath:@"CFBundleExecutable"] cString], "AppleTV") == 0) return 1; } // This may work on AppleTV 1.1 also but I am not sure. This is a quick hack to force 1.0 to work. fileData = [NSData dataWithContentsOfFile:@"/System/Library/MonitorPanels/AppleDisplay.monitorPanels/Contents/Resources/TVOptions.monitorPanel/Contents/Info.plist"]; dict = [NSPropertyListSerialization propertyListFromData:fileData mutabilityOption:kCFPropertyListImmutable format:NULL errorDescription:&error]; if(!dict) { NSLog(@"%s", error); } else { if (strcmp([[dict valueForKeyPath:@"CFBundleExecutable"] cString], "TVOptions") == 0) return 1; } fileData = [NSData dataWithContentsOfFile:@"/System/Library/Extensions/AppleAirPort2.kext/Contents/Info.plist"]; dict = [NSPropertyListSerialization propertyListFromData:fileData mutabilityOption:kCFPropertyListImmutable format:NULL errorDescription:&error]; if(!dict) { NSLog(@"%s", error); } else { if ([[dict valueForKeyPath:@"IOKitPersonalities.Broadcom PCI.APMonitorMode"] boolValue]) return 1; } fileData = [NSData dataWithContentsOfFile:@"/System/Library/Extensions/IO80211Family.kext/Contents/PlugIns/AppleAirPortBrcm4311.kext/Contents/Info.plist"]; dict = [NSPropertyListSerialization propertyListFromData:fileData mutabilityOption:kCFPropertyListImmutable format:NULL errorDescription:&error]; if(!dict) { NSLog(@"%s", error); } else { if ([[dict valueForKeyPath:@"IOKitPersonalities.Broadcom PCI.APMonitorMode"] boolValue]) return 1; } return -1; } int darwin_bcom_enablemonitorfile(const char *c_filename) { NSDictionary *dict; NSData *data; NSString *fileName; NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; fileName = [[NSString alloc] initWithCString:c_filename]; if (chmod([fileName cString], (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0 && errno != ENOENT) { return -1; } data = [NSData dataWithContentsOfFile:fileName]; if(!data) return 0; dict = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:kCFPropertyListMutableContainers format:NULL errorDescription:Nil]; if(!dict) return 0; [dict setValue:[NSNumber numberWithBool:true] forKeyPath:@"IOKitPersonalities.Broadcom PCI.APMonitorMode"]; [[NSPropertyListSerialization dataFromPropertyList:dict format:kCFPropertyListXMLFormat_v1_0 errorDescription:nil] writeToFile:fileName atomically:NO]; if (chmod([fileName cString], (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0 && errno != ENOENT) { return -1; } return 1; } int darwin_bcom_enablemonitor() { int ret, i; NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; char cmd[1024]; ret = darwin_bcom_enablemonitorfile("/System/Library/Extensions/AppleAirPort2.kext/Contents/Info.plist") || darwin_bcom_enablemonitorfile("/System/Library/Extensions/IO80211Family.kext/Contents/PlugIns/AppleAirPortBrcm4311.kext/Contents/Info.plist"); if (ret == 0) { return -1; } if (unlink("/System/Library/Extensions.kextcache") < 0 && errno != ENOENT) return -1; snprintf(cmd, 1024, "/usr/sbin/kextcache -k /System/Library/Extensions"); if (system(cmd) != 0) return -1; if (unlink("/System/Library/Extensions.mkext") < 0 && errno != ENOENT) return -1; /* Throw a warning at the user and wait */ fprintf(stderr, "ATTENTION: Kismet has enabled rfmon on your devices, however " "to activate it, the kernel modules must be reloaded. There have " "been reports of this causing a system crash. Kismet will wait 10 " "seconds before attempting to reload the kernel modules. Press " "control-c now to cancel reloading modules and reboot manually if " "you do not want to proceed!\n\n"); sleep(10); /* we don't check the failure codes since we don't know which driver we're * using... Also according to geordi we have to thrash the unload because * sometimes it just refuses to unload the module. Highly inelegant. */ for (i = 0; i < 10; i++) { snprintf(cmd, 1024, "/sbin/kextunload -b com.apple.driver.AppleAirPort2" ">/dev/null 2>/dev/null"); system(cmd); snprintf(cmd, 1024, "/sbin/kextunload -b " "com.apple.driver.AppleAirPortBrcm4311 >/dev/null 2>/dev/null"); system(cmd); } /* Try to reload them */ snprintf(cmd, 1024, "/sbin/kextload /System/Library/Extensions/AppleAirPort2.kext" ">/dev/null 2>/dev/null"); system(cmd); snprintf(cmd, 1024, "/sbin/kextload " "/System/Library/Extensions/AppleAirPortBrcm4311.kext " ">/dev/null 2>/dev/null"); system(cmd); fprintf(stderr, "ATTENTION: Completed trying to reload the kernel modules. " "Sometimes this doesn't work, if Kismet does not start properly " "you will need to manually reboot.\n"); sleep(5); return 1; } void *darwin_allocate_interface(const char *in_iface) { DarwinWifi *darwin = [[DarwinWifi alloc] initWithInterface:[[NSString alloc] initWithUTF8String:in_iface]]; return (void *) darwin; } void darwin_free_interface(void *in_darwin) { // TODO } int darwin_set_channel(unsigned int in_channel, char *ret_err, void *in_darwin) { DarwinWifi *darwin = (DarwinWifi *) in_darwin; BOOL result; NSError *err; result = [darwin setChannel:in_channel error:ret_err]; if (!result) { return -1; } return 1; } int darwin_get_corewifi(void *in_darwin) { DarwinWifi *darwin = (DarwinWifi *) in_darwin; return [darwin getCoreWireless]; } void darwin_disassociate(void *in_darwin) { DarwinWifi *darwin = (DarwinWifi *) in_darwin; [darwin disAssociate]; } int darwin_get_channels(const char *in_iface, int **ret_channels) { NSArray *supported; int *ret = NULL; int x = 0; DarwinWifi *darwin = [[DarwinWifi alloc] initWithInterface:[[NSString alloc] initWithUTF8String:in_iface]]; supported = [darwin getSupportedChannels]; if (supported == nil) { *ret_channels = NULL; return 0; } ret = (int *) malloc(sizeof(int) * [supported count]); for (id sup in supported) { ret[x++] = [sup intValue]; } *ret_channels = ret; x = [supported count]; return x; } #endif kismet-2013-03-R1b/messagebus.cc0000664000175000017500000000344012124602454016121 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "messagebus.h" void StdoutMessageClient::ProcessMessage(string in_msg, int in_flags) { if (in_flags & (MSGFLAG_ERROR | MSGFLAG_FATAL)) fprintf(stderr, "ERROR: %s\n", in_msg.c_str()); else fprintf(stdout, "NOTICE: %s\n", in_msg.c_str()); return; } void MessageBus::InjectMessage(string in_msg, int in_flags) { for (unsigned int x = 0; x < subscribers.size(); x++) { if (subscribers[x]->mask & in_flags) subscribers[x]->client->ProcessMessage(in_msg, in_flags); } return; } void MessageBus::RegisterClient(MessageClient *in_subscriber, int in_mask) { busclient *bc = new busclient; bc->client = in_subscriber; bc->mask = in_mask; subscribers.push_back(bc); return; } void MessageBus::RemoveClient(MessageClient *in_unsubscriber) { for (unsigned int x = 0; x < subscribers.size(); x++) { if (subscribers[x]->client == in_unsubscriber) { subscribers.erase(subscribers.begin() + x); return; } } return; } kismet-2013-03-R1b/soundcontrol.h0000664000175000017500000000427612124602454016366 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef __SOUNDCONTROL_H__ #define __SOUNDCONTROL_H__ #include "globalregistry.h" #include "pollable.h" #include "ipc_remote.h" #define SPEECH_ENCODING_NORMAL 0 #define SPEECH_ENCODING_NATO 1 #define SPEECH_ENCODING_SPELL 2 struct soundcontrol_ipc_frame { time_t timestamp; char player[256]; int opt; char msg[0]; }; extern char speech_alphabet[2][36][12]; class SoundControl { public: SoundControl(); SoundControl(GlobalRegistry *in_globalreg); virtual ~SoundControl(); // Kill void Shutdown(); int PlaySound(string in_text); int SayText(string in_text); string EncodeSpeechString(string in_str); int LocalPlay(string player, string wav); int LocalSpeech(string player, int in_festival, string text); void SetSoundEnable(int en) { sound_enable = en; } void SetSpeechEnable(int en) { speech_enable = en; } void SetSpeechEncode(string in_encode); void SetPlayer(string in_pl) { player = in_pl; } void SetSpeaker(string in_sp, string in_type) { speaker = in_sp; speech_festival = (StrLower(in_type) != "raw"); } protected: int SpawnChildProcess(); int SendPacket(string text, string in_player, int opt, int id); int nulfd; GlobalRegistry *globalreg; IPCRemote *sound_remote; int shutdown; uint32_t sound_ipc_id, speech_ipc_id; string player, speaker; int sound_enable, speech_enable, speech_festival; friend int sound_ipc_callback(IPC_CMD_PARMS); int speech_encoding; }; #endif kismet-2013-03-R1b/manuf.h0000664000175000017500000000270512124602454014736 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __MANUF_H__ #define __MANUF_H__ #include "config.h" #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include "util.h" #include "globalregistry.h" class Manuf { public: Manuf() { fprintf(stderr, "FATAL OOPS: Manuf()\n"); exit(1); } Manuf(GlobalRegistry *in_globalreg); void IndexOUI(); string LookupOUI(mac_addr in_mac); struct index_pos { uint32_t oui; fpos_t pos; }; struct manuf_data { uint32_t oui; string manuf; }; protected: GlobalRegistry *globalreg; vector index_vec; map oui_map; FILE *mfile; }; #endif kismet-2013-03-R1b/dumpfile_pcap.cc0000664000175000017500000003641512124602454016603 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef HAVE_LIBPCAP #include #include "endian_magic.h" #include "dumpfile_pcap.h" #include "packetsource_pcap.h" int dumpfilepcap_chain_hook(CHAINCALL_PARMS) { Dumpfile_Pcap *auxptr = (Dumpfile_Pcap *) auxdata; return auxptr->chain_handler(in_pack); } Dumpfile_Pcap::Dumpfile_Pcap() { fprintf(stderr, "FATAL OOPS: Dumpfile_Pcap called with no globalreg\n"); exit(1); } Dumpfile_Pcap::Dumpfile_Pcap(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; parent = NULL; type = "pcapdump"; // Default to dot11 dlt = DLT_IEEE802_11; cbfilter = NULL; cbaux = NULL; Startup_Dumpfile(); } Dumpfile_Pcap::Dumpfile_Pcap(GlobalRegistry *in_globalreg, string in_type, int in_dlt, Dumpfile_Pcap *in_parent, dumpfile_pcap_filter_cb in_filter, void *in_aux) : Dumpfile(in_globalreg) { globalreg = in_globalreg; type = in_type; parent = in_parent; cbfilter = in_filter; cbaux = in_aux; // Use whatever DLT we got dlt = in_dlt; Startup_Dumpfile(); } void Dumpfile_Pcap::Startup_Dumpfile() { // Default DLT to the basic type int fdlt = dlt; dumpfile = NULL; dumper = NULL; if (globalreg->sourcetracker == NULL) { fprintf(stderr, "FATAL OOPS: Sourcetracker missing before Dumpfile_Pcap\n"); exit(1); } // Process a resume request dumpformat = dump_unknown; if (globalreg->kismet_config->FetchOpt(type + "format") == "ppi") { #ifndef HAVE_PPI _MSG("Cannot log in PPI format, the libpcap available when Kismet was " "compiled did not support PPI, defaulting to basic packet format.", MSGFLAG_ERROR); #else _MSG("Pcap log in PPI format", MSGFLAG_INFO); dumpformat = dump_ppi; // Set us to PPI fdlt = DLT_PPI; #endif } else { _MSG("Pcap logging for type " + type, MSGFLAG_INFO); } // Find the file name if ((fname = ProcessConfigOpt(type)) == "" || globalreg->fatal_condition) { return; } dumpfile = pcap_open_dead(fdlt, MAX_PACKET_LEN); if (dumpfile == NULL) { _MSG("Failed to open pcap dump file '" + fname + "': " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } dumper = pcap_dump_open(dumpfile, fname.c_str()); if (dumper == NULL) { _MSG("Failed to open pcap dump file '" + fname + "': " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Opened pcapdump log file '" + fname + "'", MSGFLAG_INFO); beaconlog = 1; phylog = 1; corruptlog = 1; globalreg->packetchain->RegisterHandler(&dumpfilepcap_chain_hook, this, CHAINPOS_LOGGING, -100); globalreg->RegisterDumpFile(this); } Dumpfile_Pcap::~Dumpfile_Pcap() { globalreg->packetchain->RemoveHandler(&dumpfilepcap_chain_hook, CHAINPOS_LOGGING); // Close files if (dumper != NULL) { Flush(); pcap_dump_flush(dumper); pcap_dump_close(dumper); } if (dumpfile != NULL) { pcap_close(dumpfile); } dumper = NULL; dumpfile = NULL; } int Dumpfile_Pcap::Flush() { if (dumper == NULL || dumpfile == NULL) return 0; pcap_dump_flush(dumper); return 1; } void Dumpfile_Pcap::RegisterPPICallback(dumpfile_ppi_cb in_cb, void *in_aux) { for (unsigned int x = 0; x < ppi_cb_vec.size(); x++) { if (ppi_cb_vec[x].cb == in_cb && ppi_cb_vec[x].aux == in_aux) return; } ppi_cb_rec r; r.cb = in_cb; r.aux = in_aux; ppi_cb_vec.push_back(r); } void Dumpfile_Pcap::RemovePPICallback(dumpfile_ppi_cb in_cb, void *in_aux) { for (unsigned int x = 0; x < ppi_cb_vec.size(); x++) { if (ppi_cb_vec[x].cb == in_cb && ppi_cb_vec[x].aux == in_aux) { ppi_cb_vec.erase(ppi_cb_vec.begin() + x); return; } } } int Dumpfile_Pcap::chain_handler(kis_packet *in_pack) { // Grab the mangled frame if we have it, then try to grab up the list of // data types and die if we can't get anything kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); // Grab the generic mangled frame kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); kis_layer1_packinfo *radioinfo = (kis_layer1_packinfo *) in_pack->fetch(_PCM(PACK_COMP_RADIODATA)); kis_gps_packinfo *gpsdata = (kis_gps_packinfo *) in_pack->fetch(_PCM(PACK_COMP_GPS)); kis_fcs_bytes *fcsdata = (kis_fcs_bytes *) in_pack->fetch(_PCM(PACK_COMP_FCSBYTES)); if (cbfilter != NULL) { // If we have a filter, grab the data using that chunk = (*cbfilter)(globalreg, in_pack, cbaux); } else if (chunk == NULL) { // Look for the 802.11 frame if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { // Look for any link frame, we'll check the DLT soon chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME)); } } // If after all of that we still didn't find a packet if (chunk == NULL) return 0; if (chunk != NULL && (chunk->length < 0 || chunk->length > MAX_PACKET_LEN)) { _MSG("Weird frame in pcap logger with the wrong size...", MSGFLAG_ERROR); return 0; } // Make sure we have the right DLT for simple matching conditions if (cbfilter == NULL && chunk->dlt != dlt) { return 0; } int dump_offset = 0; if (packinfo != NULL) { if (phylog == 0 && packinfo->type == packet_phy) return 0; if (corruptlog == 0 && packinfo->corrupt) return 0; if (beaconlog == 0 && packinfo->type == packet_management && packinfo->subtype == packet_sub_beacon) { macmap::iterator bcmi = bssid_csum_map.find(packinfo->bssid_mac); if (bcmi != bssid_csum_map.end() && *(bcmi->second) == packinfo->ssid_csum) { return 0; } bssid_csum_map.insert(packinfo->bssid_mac, packinfo->ssid_csum); } } unsigned int dump_len = 0; if (chunk != NULL) dump_len += chunk->length; u_char *dump_data = NULL; // Assemble the full packet if (dumpformat == dump_ppi) { ppi_packet_header *ppi_ph; int gps_tagsize = 0; //include struct ppi fieldheader int dot11common_tagsize = 0; //include ppi_fieldheader unsigned int ppi_len = 0; unsigned int ppi_pos = sizeof(ppi_packet_header); /* The size of the gps tag varies depending if we have altitude or not * we do all of the length math up front, and throughout the rest of the * function make our decision based on the length, not the gpsdata. * this helps keep logic error minimized. */ if (gpsdata != NULL) { gps_tagsize = sizeof(ppi_gps_hdr); //12 if (gpsdata->gps_fix <= 1) //no fix gps_tagsize = 0; //dont bother storing anything if (gpsdata->gps_fix >= 2) gps_tagsize += 12; // lon, lat, appid, if (gpsdata->gps_fix >= 3) gps_tagsize +=4; // altitude //Could eventually include hdop, vdop using simillar scheme here } /* although dot11common tags are constant size, we follow the same pattern here*/ if (radioinfo != NULL) { dot11common_tagsize = sizeof(ppi_80211_common); if (fcsdata != NULL) dump_len += 4; } //printf("sizeof ppi_gps_hdr:%d\n", sizeof(ppi_gps_hdr)); //printf("Computed gps tagsize of %d\n", gps_tagsize); //printf("Computed dot11common tagsize of %d\n", dot11common_tagsize); //printf("Sizeof ppi_packetheader: %d\n", sizeof(ppi_packet_header)); ppi_len += sizeof(ppi_packet_header); ppi_len += gps_tagsize; ppi_len += dot11common_tagsize; //printf("ppi_len=%d\n", ppi_len); //With the static-ppi fields out of the way, handle any dynamic ones //(f.ex) plugin-spectool // Collate the allocation sizes of any callbacks for (unsigned int p = 0; p < ppi_cb_vec.size(); p++) { ppi_len += (*(ppi_cb_vec[p].cb))(globalreg, 1, in_pack, NULL, 0, ppi_cb_vec[p].aux); } // If we have a parent, call them if (parent != NULL) { for (unsigned int p = 0; p < parent->ppi_cb_vec.size(); p++) { ppi_len += (*(parent->ppi_cb_vec[p].cb))(globalreg, 1, in_pack, NULL, 0, parent->ppi_cb_vec[p].aux); } } dump_len += ppi_len; //dumplen now accoutns for all ppi data //printf("dump_len=%d\n", dump_len); if (dump_len == 0 && ppi_len == 0) return 0; dump_data = new u_char[dump_len]; //memset(dump_data, 0xcc, dump_len); //Good for debugging ppi stuff. ppi_ph = (ppi_packet_header *) dump_data; ppi_ph->pph_version = 0; ppi_ph->pph_flags = 0; ppi_ph->pph_len = kis_htole16(ppi_len); // Use the DLT in the PPI internal ppi_ph->pph_dlt = kis_htole32(dlt); //First lay out the GPS tag, if applicable if (gpsdata != NULL) { unsigned int gps_data_offt = 0; //offsets to fields, from begging of field data. if (gps_tagsize > 0) { ppi_gps_hdr *ppigps = NULL; union block { uint8_t u8; uint16_t u16; uint32_t u32; } *u; //printf("debug - logging ppi gps packet. gps_tagsize: %d\n", gps_tagsize); ppigps = (ppi_gps_hdr *) &(dump_data[ppi_pos]); ppigps->pfh_datatype = kis_htole16(PPI_FIELD_GPS); // Header + lat/lon minus PPI overhead. ppigps->pfh_datalen = gps_tagsize - 4; //subtract ppi fieldheader ppigps->version = 2; ppigps->fields_present = PPI_GPS_FLAG_LAT | PPI_GPS_FLAG_LON | PPI_GPS_FLAG_APPID; //GPSLAT //printf("lat: %3.7f %f \n", gpsdata->lat, gpsdata->lat); u = (block *) &(ppigps->field_data[gps_data_offt]); u->u32 = kis_htole32(double_to_fixed3_7(gpsdata->lat)); gps_data_offt += 4; //GPSLON //printf("lon: %3.7f %f\n", gpsdata->lon, gpsdata->lon); u = (block *) &(ppigps->field_data[gps_data_offt]); u->u32 = kis_htole32(double_to_fixed3_7(gpsdata->lon)); gps_data_offt += 4; //GPSALT if (gps_tagsize >= 28) //include alt { u = (block *) &(ppigps->field_data[gps_data_offt]); u->u32 = kis_htole32(double_to_fixed6_4(gpsdata->alt)); //u->u32 = kis_htole32(0x6b484390); gps_data_offt += 4; ppigps->fields_present |= PPI_GPS_FLAG_ALT; } //APPID //printf("gps_data_offt %d gpslen = %d\n", gps_data_offt,ppigps->gps_len); u = (block *) &(ppigps->field_data[gps_data_offt]); u->u32 = kis_htole32(0x0053494B); //KIS0 gps_data_offt += 4; ppigps->magic = PPI_GPS_MAGIC; ppigps->gps_len = gps_tagsize - 4; //subtract ppi fieldheader // Convert endian state ppigps->fields_present = kis_htole32(ppigps->fields_present); ppigps->pfh_datalen = kis_htole32(ppigps->pfh_datalen); ppigps->gps_len = kis_htole16(ppigps->gps_len); //Advance ppi cursor for other PPI tags. ppi_pos += gps_tagsize; }//tagsize > 0 }//gpsdata present dump_offset = ppi_pos; if (radioinfo != NULL) { ppi_80211_common *ppi_common; ppi_common = (ppi_80211_common *) &(dump_data[ppi_pos]); ppi_pos += sizeof(ppi_80211_common); ppi_common->pfh_datatype = kis_htole16(PPI_FIELD_11COMMON); ppi_common->pfh_datalen = kis_htole16(sizeof(ppi_80211_common) - sizeof(ppi_field_header)); if (packinfo != NULL) ppi_common->tsf_timer = kis_htole64(packinfo->timestamp); else ppi_common->tsf_timer = 0; // Assemble the flags in host mode then convert them all at once ppi_common->flags = 0; if (packinfo != NULL && packinfo->corrupt) ppi_common->flags |= PPI_80211_FLAG_PHYERROR; if (fcsdata != NULL) { ppi_common->flags |= PPI_80211_FLAG_FCS; if (fcsdata->fcsvalid == 0) ppi_common->flags |= PPI_80211_FLAG_INVALFCS; } ppi_common->flags = kis_htole16(ppi_common->flags); ppi_common->rate = kis_htole16(radioinfo->datarate / 5); ppi_common->freq_mhz = kis_htole16(radioinfo->freq_mhz); // Assemble the channel flags then endian swap them ppi_common->chan_flags = 0; switch (radioinfo->encoding) { case encoding_cck: ppi_common->chan_flags |= PPI_80211_CHFLAG_CCK; break; case encoding_ofdm: ppi_common->chan_flags |= PPI_80211_CHFLAG_OFDM; break; case encoding_dynamiccck: ppi_common->chan_flags |= PPI_80211_CHFLAG_DYNAMICCCK; break; case encoding_gfsk: ppi_common->chan_flags |= PPI_80211_CHFLAG_GFSK; break; case encoding_pbcc: case encoding_unknown: break; } switch (radioinfo->carrier) { case carrier_80211b: ppi_common->chan_flags |= (PPI_80211_CHFLAG_2GHZ | PPI_80211_CHFLAG_CCK); break; case carrier_80211bplus: ppi_common->chan_flags |= (PPI_80211_CHFLAG_2GHZ | PPI_80211_CHFLAG_CCK | PPI_80211_CHFLAG_TURBO); break; case carrier_80211a: ppi_common->chan_flags |= (PPI_80211_CHFLAG_5GHZ | PPI_80211_CHFLAG_OFDM); break; case carrier_80211g: // Could be PPI_80211_CHFLAG_OFDM or PPI_80211_CHFLAG_DYNAMICCCK ppi_common->chan_flags |= PPI_80211_CHFLAG_2GHZ; break; case carrier_80211fhss: ppi_common->chan_flags |= (PPI_80211_CHFLAG_2GHZ | PPI_80211_CHFLAG_GFSK); break; case carrier_80211dsss: ppi_common->chan_flags |= PPI_80211_CHFLAG_2GHZ; break; case carrier_80211n20: case carrier_80211n40: // FIXME Dunno how to restore spectrum ppi_common->chan_flags |= PPI_80211_CHFLAG_OFDM; break; case carrier_unknown: break; } ppi_common->chan_flags = kis_htole16(ppi_common->chan_flags); ppi_common->fhss_hopset = 0; ppi_common->fhss_pattern = 0; ppi_common->signal_dbm = radioinfo->signal_dbm; ppi_common->noise_dbm = radioinfo->noise_dbm; } // Collate the allocation sizes of any callbacks for (unsigned int p = 0; p < ppi_cb_vec.size(); p++) { // Ignore errors for now ppi_pos = (*(ppi_cb_vec[p].cb))(globalreg, 0, in_pack, dump_data, ppi_pos, ppi_cb_vec[p].aux); } dump_offset = ppi_pos; } if (dump_len == 0) { // printf("debug - nothing to dump\n"); return 0; } // printf("debug - making new dump, len %d\n", dump_len); if (dump_data == NULL) dump_data = new u_char[dump_len]; // copy the packet content in, offset if necessary if (chunk != NULL) { memcpy(&(dump_data[dump_offset]), chunk->data, chunk->length); dump_offset += chunk->length; } // Lousy little hack to append the FCS after the data in PPI if (dumpformat == dump_ppi && fcsdata != NULL && chunk != NULL && radioinfo != NULL) { memcpy(&(dump_data[dump_offset]), fcsdata->fcs, 4); dump_offset += 4; } // Fake a header struct pcap_pkthdr wh; wh.ts.tv_sec = in_pack->ts.tv_sec; wh.ts.tv_usec = in_pack->ts.tv_usec; wh.caplen = wh.len = dump_len; // Dump it pcap_dump((u_char *) dumper, &wh, dump_data); delete[] dump_data; dumped_frames++; return 1; } #endif /* have_libpcap */ kismet-2013-03-R1b/channeltracker.h0000664000175000017500000000442312124602454016613 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __CHANNELTRACKER_H__ #define __CHANNELTRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "kis_netframe.h" #include "timetracker.h" #include "netracker.h" #include "packet.h" class Channeltracker { public: struct channel_record { channel_record() { channel = 0; channel_time_on = 0; packets = 0; packets_delta = 0; usec_used = 0; bytes_seen = 0; bytes_delta = 0; sent_reset = 0; max_signal_dbm = -256; max_signal_rssi = 0; max_noise_dbm = -256; max_noise_rssi = 0; } int sent_reset; uint32_t channel; int channel_time_on; int packets; int packets_delta; // Signal data (within the past polling period) int max_signal_dbm; int max_signal_rssi; int max_noise_dbm; int max_noise_rssi; // Usec used long int usec_used; // Total and delta long int bytes_seen; long int bytes_delta; // Total on this channel macmap seen_networks; macmap delta_networks; }; Channeltracker() { fprintf(stderr, "FATAL OOPS: Channeltracker called without globalreg\n"); exit(1); } Channeltracker(GlobalRegistry *in_globalreg); ~Channeltracker(); void ChainHandler(kis_packet *in_pack); void ChanTimer(); protected: GlobalRegistry *globalreg; map channel_map; int chan_timer_id; int chan_proto_id; }; #endif kismet-2013-03-R1b/install-sh0000775000175000017500000001273612124602454015470 0ustar dragorndragorn#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 kismet-2013-03-R1b/kismet_client.cc0000664000175000017500000002474512124602454016630 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #define KISMET_CLIENT #include "version.h" #include #include #include #include #include "getopt.h" #include #include #include #include #include #include #include #include "util.h" #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "timetracker.h" #include "soundcontrol.h" #include "ipc_remote.h" #include "kis_clinetframe.h" #include "kis_panel_widgets.h" #include "kis_panel_windows.h" #include "kis_panel_frontend.h" #ifndef exec_name char *exec_name; #endif // One of our few globals in this file int glob_linewrap = 1; int glob_silent = 0; // Message clients that are attached at the master level // Smart standard out client that understands the silence options class SmartStdoutMessageClient : public MessageClient { public: SmartStdoutMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~SmartStdoutMessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; void SmartStdoutMessageClient::ProcessMessage(string in_msg, int in_flags) { return; #if 0 if (glob_silent) return; if ((in_flags & MSGFLAG_DEBUG)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("DEBUG: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "DEBUG: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_LOCAL)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("LOCAL: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "LOCAL: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_INFO)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("INFO: " + in_msg, 6, 80).c_str()); else fprintf(stdout, "INFO: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ERROR)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ERROR: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "ERROR: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ALERT)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ALERT: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "ALERT: %s\n", in_msg.c_str()); } else if (in_flags & MSGFLAG_FATAL) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap("FATAL: " + in_msg, 7, 80).c_str()); else fprintf(stderr, "FATAL: %s\n", in_msg.c_str()); } return; #endif } // Queue of fatal alert conditions to spew back out at the end class FatalQueueMessageClient : public MessageClient { public: FatalQueueMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~FatalQueueMessageClient() { } void ProcessMessage(string in_msg, int in_flags); void DumpFatals(); protected: vector fatalqueue; }; void FatalQueueMessageClient::ProcessMessage(string in_msg, int in_flags) { // We only get passed fatal stuff so save a test fatalqueue.push_back(in_msg); } void FatalQueueMessageClient::DumpFatals() { for (unsigned int x = 0; x < fatalqueue.size(); x++) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap("FATAL: " + fatalqueue[x], 7, 80).c_str()); else fprintf(stderr, "FATAL: %s\n", fatalqueue[x].c_str()); } } // This needs to be a global but nothing outside of this main file will // use it, so we don't have to worry much about putting it in the globalreg. FatalQueueMessageClient *fqmescli = NULL; // Ultimate registry of global components GlobalRegistry *globalregistry = NULL; void CatchChild(int sig) { int status; pid_t pid; while (1) { pid = waitpid(-1, &status, WNOHANG); if (pid != 0) break; } if (pid < 0) { return; } pid_fail frec; frec.pid = pid; frec.status = status; globalregistry->sigchild_vec.push_back(frec); } // Catch our interrupt void CatchShutdown(int sig) { /* if (sig == SIGPIPE) fprintf(stderr, "FATAL: A pipe closed unexpectedly, trying to shut down " "cleanly...\n"); */ // Start a short shutdown cycle for 2 seconds fprintf(stderr, "\n*** KISMET CLIENT IS SHUTTING DOWN ***\n"); globalregistry->spindown = 1; // Kill the sound entirely globalregistry->soundctl->Shutdown(); time_t shutdown_target = time(0) + 5; int max_fd = 0; fd_set rset, wset; struct timeval tm; while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) { break; } if (time(0) >= shutdown_target) { break; } // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); if (max_fd == 0) break; tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { break; } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { break; } } } // This kicks off the curses teardown entirely if (globalregistry->panel_interface != NULL) { globalregistry->panel_interface->Shutdown(); delete globalregistry->panel_interface; } // Be noisy if (globalregistry->fatal_condition) { fprintf(stderr, "\n*** KISMET CLIENT SHUTTING DOWN. ***\n"); } // Dump fatal errors again if (fqmescli != NULL) fqmescli->DumpFatals(); fprintf(stderr, "Kismet client exiting.\n"); exit(0); } void CatchWinch(int sig) { globalregistry->winch = true; } int Usage(char *argv) { printf("Usage: %s [OPTION]\n", argv); printf(" *** Generic Options ***\n"); printf(" -h, --help The obvious\n"); exit(1); } int main(int argc, char *argv[], char *envp[]) { exec_name = argv[0]; char errstr[STATUS_MAX]; int option_idx = 0; // ------ WE MAY BE RUNNING AS ROOT ------ // Catch the interrupt handler to shut down signal(SIGINT, CatchShutdown); signal(SIGTERM, CatchShutdown); signal(SIGHUP, CatchShutdown); signal(SIGQUIT, CatchShutdown); signal(SIGCHLD, CatchChild); signal(SIGPIPE, SIG_IGN); // Start filling in key components of the globalregistry globalregistry = new GlobalRegistry; globalregistry->version_major = VERSION_MAJOR; globalregistry->version_minor = VERSION_MINOR; globalregistry->version_tiny = VERSION_TINY; globalregistry->revision = REVISION; globalregistry->revdate = REVDATE; // Copy for modules globalregistry->argc = argc; globalregistry->argv = argv; globalregistry->envp = envp; // First order - create our message bus and our client for outputting globalregistry->messagebus = new MessageBus; // Create a smart stdout client and allocate the fatal message client, // add them to the messagebus SmartStdoutMessageClient *smartmsgcli = new SmartStdoutMessageClient(globalregistry, NULL); fqmescli = new FatalQueueMessageClient(globalregistry, NULL); globalregistry->messagebus->RegisterClient(fqmescli, MSGFLAG_FATAL); globalregistry->messagebus->RegisterClient(smartmsgcli, MSGFLAG_ALL); // Allocate some other critical stuff globalregistry->timetracker = new Timetracker(globalregistry); // Turn off the getopt error reporting opterr = 0; // Standard getopt parse run static struct option main_longopt[] = { { "version", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; while (1) { int r = getopt_long(argc, argv, "-hv", main_longopt, &option_idx); if (r < 0) break; if (r == 'h') { Usage(argv[0]); exit(1); } else if (r == 'v') { printf("Kismet %s-%s-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_TINY); exit(1); } } // Create the sound control globalregistry->soundctl = new SoundControl(globalregistry); // Create the panel interface globalregistry->panel_interface = new KisPanelInterface(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Make the main panel and assign it to the interface Kis_Main_Panel *mainp = new Kis_Main_Panel(globalregistry, globalregistry->panel_interface); mainp->Position(0, 0, LINES, COLS); globalregistry->panel_interface->AddPanel(mainp); mainp->Startup(); // Kickstart our saved plugins globalregistry->panel_interface->LoadPlugins(); #if 0 KisNetClient *kcli = new KisNetClient(globalregistry); kcli->Connect("tcp://localhost:2501", 1); #endif signal(SIGWINCH, CatchWinch); globalregistry->messagebus->InjectMessage("Welcome to the Kismet Newcore " "Client... Press '`' or '~' to " "activate menus.", MSGFLAG_INFO); int max_fd = 0; fd_set rset, wset; struct timeval tm; // Core loop while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } if (globalregistry->winch) { globalregistry->winch = false; if (globalregistry->panel_interface != NULL) globalregistry->panel_interface->ResizeInterface(); } globalregistry->timetracker->Tick(); for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } } CatchShutdown(-1); } kismet-2013-03-R1b/kis_panel_preferences.h0000664000175000017500000002413212124602454020154 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_PREFERENCES_H__ #define __KIS_PANEL_PREFERENCES_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "netracker.h" #include "kis_clinetframe.h" #include "kis_panel_widgets.h" // Common struct for column/extra prefs struct common_col_pref { const char *pref; const char *name; int ref; }; // Color picker - draws all the colors and lets you pick one with // left/right/space|enter class Kis_ColorPref_Component : public Kis_Panel_Component { public: Kis_ColorPref_Component() { fprintf(stderr, "FATAL OOPS: Kis_ColorPref_Component()\n"); exit(1); } Kis_ColorPref_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_ColorPref_Component(); virtual void DrawComponent(); virtual void Activate(int sub); virtual void Deactivate(); virtual int KeyPress(int in_key); virtual void SetColor(string in_color); virtual string GetColor(); protected: int active; int cpos; int colors[16]; int text_color; }; class Kis_OrderlistPref_Component : public Kis_Scrollable_Table { public: Kis_OrderlistPref_Component() { fprintf(stderr, "FATAL OOPS: Kis_OrderlistPref_Component()\n"); exit(1); } Kis_OrderlistPref_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_OrderlistPref_Component(); virtual int KeyPress(int in_key); virtual void SetOrderable(int in_order); // Set the field of the columns which controls enabled, we dynamically // alter the row_data here. Set the "Yes" "No" field text, this is // also used to compare for enabled fields virtual void SetEnableField(int in_field, string in_yes, string in_no); // Set the string order field (ie, column name) virtual void SetColumnField(int in_field); // Get a config-file style ordered string of the enabled columns virtual string GetStringOrderList(); protected: int orderable; int enable_fid, column_fid; string field_yes, field_no; }; // I'm un-thrilled about this approach but it'll do class Kis_ColorPref_Picker : public Kis_Panel { public: Kis_ColorPref_Picker() { fprintf(stderr, "FATAL OOPS: Kis_ColorPref_Picker()\n"); exit(1); } Kis_ColorPref_Picker(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_ColorPref_Picker(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); virtual void LinkColorPref(string in_prefname); virtual void ButtonAction(Kis_Panel_Component *in_button); protected: Kis_Button *okbutton, *cancelbutton; Kis_ColorPref_Component *fgcolor, *bgcolor; Kis_Panel_Packbox *vbox, *hbox; string prefname; }; class Kis_ColorPref_Panel : public Kis_Panel { // Plugin picker lists .so files in the plugin director(ies) and lets // the user pick one to load. public: Kis_ColorPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_ColorPref_Panel called w/out globalreg\n"); exit(1); } Kis_ColorPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_ColorPref_Panel(); virtual void DrawPanel(); virtual void AddColorPref(string pref, string name); virtual void SelectedAction(Kis_Panel_Component *component, int listkey); struct cprefpair { string text, pref; }; protected: Kis_Scrollable_Table *colorlist; Kis_Button *closebutton; Kis_Panel_Packbox *vbox; vector listedcolors; }; class Kis_AutoConPref_Panel : public Kis_Panel { public: Kis_AutoConPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Connect_Panel called w/out globalreg\n"); exit(1); } Kis_AutoConPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_AutoConPref_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); protected: Kis_Single_Input *hostname; Kis_Single_Input *hostport; Kis_Checkbox *autoconcheck; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; }; class Kis_ColumnPref_Panel : public Kis_Panel { public: Kis_ColumnPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_ColumnPref_Panel called w/out globalreg\n"); exit(1); } Kis_ColumnPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_ColumnPref_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); // Add a column to the understood options. These should ALL be populated // BEFORE calling ColumnPref to link it to a pref value virtual void AddColumn(string colname, string description); // Link to a column preference field virtual void ColumnPref(string pref, string name); virtual void ButtonAction(Kis_Panel_Component *in_button); struct pref_cols{ string colname; string description; int queued; }; protected: Kis_OrderlistPref_Component *orderlist; Kis_Free_Text *helptext; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; string pref, prefname; vector pref_vec; }; class Kis_Keyshort_Panel : public Kis_Panel { public: Kis_Keyshort_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Keyshort_Panel called w/out globalreg\n"); exit(1); } Kis_Keyshort_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_Keyshort_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); // Add a shortcut name virtual void AddShortcut(string prefname, string dispname); virtual void ButtonAction(Kis_Panel_Component *in_button); struct pref_shorts { string prefname; string dispname; char key; }; protected: Kis_OrderlistPref_Component *orderlist; Kis_Free_Text *helptext; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; vector pref_vec; }; class Kis_GpsPref_Panel : public Kis_Panel { public: Kis_GpsPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Gps_Panel called w/out globalreg\n"); exit(1); } Kis_GpsPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_GpsPref_Panel(); virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); protected: Kis_Radiobutton *metrad, *engrad; Kis_Free_Text *helptext; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *cbox, *bbox; }; class Kis_StartupPref_Panel : public Kis_Panel { public: Kis_StartupPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Gps_Panel called w/out globalreg\n"); exit(1); } Kis_StartupPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_StartupPref_Panel(); virtual void ButtonAction(Kis_Panel_Component *in_button); protected: Kis_Checkbox *startkis_check, *startkisprompt_check, *startcons_check, *stopkis_check, *stopkisprompt_check; Kis_Button *okbutton; Kis_Button *cancelbutton; Kis_Panel_Packbox *vbox, *bbox; }; #if 0 class Kis_AudioPicker_Panel : public Kis_Panel { public: Kis_AudioPicker_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AudioPicker_Panel()\n"); exit(1); } Kis_AudioPicker_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_AudioPicker_Panel(); virtual void SetPref(string in_trigger, string in_enable, string in_file); virtual void Action(Kis_Panel_Component *in_component, int in_status); protected: Kis_Filepicker *filelist; Kis_Single_Input *directory; Kis_Checkbox *enablecheck; Kis_Button *okbutton, *cancelbutton, *dirbutton; Kis_Panel_Packbox *vbox, *dbox, *bbox; string trigger; }; #endif class Kis_AudioPref_Panel : public Kis_Panel { public: Kis_AudioPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AudioPref_Panel called w/out globalreg\n"); exit(1); } Kis_AudioPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_AudioPref_Panel(); virtual void DrawPanel(); virtual void Action(Kis_Panel_Component *in_component, int in_status); protected: Kis_Scrollable_Table *audiolist; Kis_Checkbox *sound_check, *speech_check; Kis_Single_Input *sound_player; Kis_Button *config_speech_button, *close_button; Kis_Panel_Packbox *cbox, *vbox; vector keys; }; class Kis_SpeechPref_Panel : public Kis_Panel { public: Kis_SpeechPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AudioPref_Panel called w/out globalreg\n"); exit(1); } Kis_SpeechPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_SpeechPref_Panel(); virtual void Action(Kis_Panel_Component *in_component, int in_status); protected: Kis_Free_Text *speechtype_text, *speechplayer_text; Kis_Single_Input *speech_new, *speech_alert, *speech_gpslost, *speech_gpslock, *speaker; Kis_Checkbox *fest_check; Kis_Free_Text *encode_text; Kis_Radiobutton *encode_none_radio, *encode_nato_radio, *encode_spell_radio; Kis_Button *close_button; Kis_Panel_Packbox *rbox, *vbox, *vbox2; }; class Kis_WarnPref_Panel : public Kis_Panel { public: Kis_WarnPref_Panel() { fprintf(stderr, "FATAL OOPS: Kis_WarnPref_Panel()\n"); exit(1); } Kis_WarnPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf); virtual ~Kis_WarnPref_Panel(); virtual void Action(Kis_Panel_Component *in_component, int in_status); protected: Kis_Scrollable_Table *warntable; Kis_Button *closebutton; Kis_Panel_Packbox *vbox; int k; }; #endif // curses #endif // prefs kismet-2013-03-R1b/kis_clinetframe.cc0000664000175000017500000004470612124602454017134 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "util.h" #include "configfile.h" #include "kis_clinetframe.h" #include "getopt.h" int KisNetClientReconEvent(TIMEEVENT_PARMS) { ((KisNetClient *) parm)->Reconnect(); return 1; } int KisNetClientTimeoutEvent(TIMEEVENT_PARMS) { ((KisNetClient *) parm)->Timer(); return 1; } KisNetClient::KisNetClient() { fprintf(stderr, "FATAL OOPS: kisnetclient called with no globalreg\n"); exit(-1); } KisNetClient::KisNetClient(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { // We only support tcpclients for now, so just generate it all now tcpcli = new TcpClient(globalreg); netclient = tcpcli; // Link it RegisterNetworkClient(tcpcli); tcpcli->RegisterClientFramework(this); // Set to -1 so the reconnect auto-incr doesn't screw us up num_reconnects = -1; reconnect = 0; reconid = -1; cmdid = 1; last_disconnect = 0; last_read = 0; // Counter for configure level configured = 1; timerid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 5, NULL, 1, &KisNetClientTimeoutEvent, (void *) this); } KisNetClient::~KisNetClient() { KillConnection(); if (tcpcli != NULL) { delete tcpcli; tcpcli = NULL; } if (reconid > -1) globalreg->timetracker->RemoveTimer(reconid); if (timerid > -1) globalreg->timetracker->RemoveTimer(timerid); globalreg->RemovePollableSubsys(this); } int KisNetClient::Connect(string in_host, int in_reconnect) { char proto[11]; char temphost[129]; short int temport; if (sscanf(in_host.c_str(), "%10[^:]://%128[^:]:%hu", proto, temphost, &temport) != 3) { _MSG("Kismet network client could not parse host, expected the form " "proto://host:port, got '" + in_host + "'", MSGFLAG_ERROR); return -1; } if (StrLower(string(proto)) != "tcp") { _MSG("Kismet network client currently only supports the TCP protocol for " "connecting to servers.", MSGFLAG_ERROR); return -1; } snprintf(host, MAXHOSTNAMELEN, "%s", temphost); port = temport; if (in_reconnect && reconid == -1) { reconid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 5, NULL, 1, &KisNetClientReconEvent, (void *) this); reconnect = 1; } last_disconnect = 1; // Let the reconnect trigger handle the rest return Reconnect(); } int KisNetClient::KillConnection() { ClientFramework::KillConnection(); last_disconnect = time(0); // Remove all the configured protocols, they'll get re-registered by the // configure callbacks map::iterator hitr; for (hitr = handler_cb_map.begin(); hitr != handler_cb_map.end(); ++hitr) { for (unsigned int x = 0; x < hitr->second.handler_vec.size(); x++) { delete(hitr->second.handler_vec[x]); } } handler_cb_map.clear(); // Clear the supported fields proto_field_dmap.clear(); // Clear the command callback map (all commands are dead) command_cb_map.clear(); return 1; } int KisNetClient::Shutdown() { if (tcpcli != NULL) { tcpcli->FlushRings(); tcpcli->KillConnection(); } return 1; } void KisNetClient::AddConfCallback(CliConf_Callback in_cb, int in_recon, void *in_aux) { kcli_conf_rec *rec = new kcli_conf_rec; rec->auxptr = in_aux; rec->callback = in_cb; rec->on_recon = in_recon; conf_cb_vec.push_back(rec); // Call the configure function if we're already configured if (configured < 0) { (*in_cb)(globalreg, this, 0, in_aux); } } void KisNetClient::RemoveConfCallback(CliConf_Callback in_cb) { for (unsigned int x = 0; x < conf_cb_vec.size(); x++) { if (conf_cb_vec[x]->callback == in_cb) { delete conf_cb_vec[x]; conf_cb_vec.erase(conf_cb_vec.begin() + x); break; } } } int KisNetClient::RegisterProtoHandler(string in_proto, string in_fieldlist, CliProto_Callback in_cb, void *in_aux, CliCmd_Callback in_cmd_complete) { in_proto = StrLower(in_proto); /* if (handler_cb_map.find(in_proto) != handler_cb_map.end()) { _MSG("Handler for '" + in_proto + "' already registered.", MSGFLAG_ERROR); return -1; } */ // Do we know about this proto at all? map >::iterator dmitr = proto_field_dmap.find(in_proto); if (dmitr == proto_field_dmap.end()) { /* _MSG("Kis net client - trying to register for unknown protocol '" + in_proto + "'", MSGFLAG_ERROR); */ return -1; } // Break down the fields and compare against the fields we know about, make // sure they can't enable something the server doesn't understand. This is a // cheap hack around our non-async behavior that keeps us from having a good // way to return a command failure condition vector fields = StrTokenize(in_fieldlist, ","); kcli_handler_rec *rec = new kcli_handler_rec; for (unsigned int x = 0; x < fields.size(); x++) { int matched = 0; fields[x] = StrLower(fields[x]); for (unsigned int fx = 0; fx < dmitr->second.size(); fx++) { if (dmitr->second[fx].fname == fields[x]) { matched = 1; // Stack the field numbers for this callback, in reference // to the absolute field number from the CAPABILITY field. rec->local_fnums.push_back(dmitr->second[fx].fnum); } } if (matched == 0) { _MSG("Unknown field '" + fields[x] + "' requested for protocol '" + in_proto + "'", MSGFLAG_ERROR); delete rec; return -1; } } // Increase the use count for the fields we enabled, done here to preserve // fields if a compare fails for (unsigned int x = 0; x < rec->local_fnums.size(); x++) { dmitr->second[rec->local_fnums[x]].usecount++; } rec->auxptr = in_aux; rec->callback = in_cb; string combo_fieldlist; map a_l_map; int cfpos = 0; for (unsigned int x = 0; x < dmitr->second.size(); x++) { if (dmitr->second[x].usecount > 0) { // Build a linkage of absolute field number to field num we // get in response to this specific CONFIGURE command a_l_map[dmitr->second[x].fnum] = cfpos++; combo_fieldlist += dmitr->second[x].fname + ","; } } // Send the command InjectCommand("ENABLE " + in_proto + " " + combo_fieldlist, in_cmd_complete, in_aux); handler_cb_map[in_proto].fields = combo_fieldlist; handler_cb_map[in_proto].abs_to_conf_fnum_map = a_l_map; handler_cb_map[in_proto].handler_vec.push_back(rec); return 1; } void KisNetClient::RemoveProtoHandler(string in_proto, CliProto_Callback in_cb, void *in_aux) { in_proto = StrLower(in_proto); int removeproto = 1; map::iterator hitr = handler_cb_map.find(in_proto); map >::iterator dmitr = proto_field_dmap.find(in_proto); if (hitr == handler_cb_map.end() || dmitr == proto_field_dmap.end()) return; for (unsigned int x = 0; x < hitr->second.handler_vec.size(); x++) { if (hitr->second.handler_vec[x]->callback == in_cb && hitr->second.handler_vec[x]->auxptr == in_aux) { // Track use counts for fields, we won't remove this protocol if // we have anyone using it for (unsigned int fx = 0; fx < hitr->second.handler_vec[x]->local_fnums.size(); fx++) { dmitr->second[hitr->second.handler_vec[x]->local_fnums[fx]].usecount--; if (dmitr->second[hitr->second.handler_vec[x]->local_fnums[fx]].usecount > 0) removeproto = 0; } delete hitr->second.handler_vec[x]; hitr->second.handler_vec.erase(hitr->second.handler_vec.begin() + x); break; } } if (hitr->second.handler_vec.size() == 0) { removeproto = 1; handler_cb_map.erase(hitr); } if (removeproto) InjectCommand("REMOVE " + in_proto); } int KisNetClient::FetchProtoCapabilities(string in_proto, map *ret_fields) { map >::iterator pfi; pfi = proto_field_dmap.find(StrLower(in_proto)); if (pfi == proto_field_dmap.end()) return -1; for (unsigned int i = 0; i < pfi->second.size(); i++) { ret_fields->insert(make_pair(pfi->second[i].fname, pfi->second[i].fnum)); } return 1; } int KisNetClient::InjectCommand(string in_cmdtext, CliCmd_Callback in_cb, void *in_aux) { if (tcpcli->Valid() == 0) return 0; int curid = cmdid++; ostringstream cmd; cmd << "!" << curid << " " << in_cmdtext << "\n"; // fprintf(stderr, "debug - %p INJECTCMD %s\n", this, cmd.str().c_str()); if (tcpcli->WriteData((void *) cmd.str().c_str(), cmd.str().length()) < 0 || globalreg->fatal_condition) { KillConnection(); return -1; } if (in_cb != NULL) { kcli_cmdcb_rec cbr; cbr.auxptr = in_aux; cbr.callback = in_cb; command_cb_map[curid] = cbr; } return curid; } void KisNetClient::RemoveAllCmdCallbacks(CliCmd_Callback in_cb, void *in_aux) { for (map::iterator x = command_cb_map.begin(); x != command_cb_map.end(); ++x) { if (x->second.auxptr == in_aux && x->second.callback == in_cb) { command_cb_map.erase(x); x = command_cb_map.begin(); } } } int KisNetClient::Timer() { if (tcpcli == NULL) return -1; if (tcpcli->Valid() == 0) return 0; if (time(0) - last_read > 10) { _MSG("No data from Kismet server in over 10 seconds, disconnecting", MSGFLAG_ERROR); KillConnection(); return 1; } return 0; } void knc_connect_hook(GlobalRegistry *globalreg, int status, void *auxptr) { ((KisNetClient *) auxptr)->ConnectCB(status); } void KisNetClient::ConnectCB(int status) { ostringstream osstr; if (status != 0) { osstr << "Could not connect to Kismet server '" << host << ":" << port << "' (" + string(strerror(status)) + ") will attempt to reconnect in 5 " "seconds."; _MSG(osstr.str(), MSGFLAG_ERROR); last_disconnect = globalreg->timestamp.tv_sec; return; } osstr << "Established connection with Kismet server '" << host << ":" << port << "'"; _MSG(osstr.str(), MSGFLAG_INFO); last_disconnect = 0; // Set the start time and initialize configured to 1 last_read = time_connected = time(0); configured = 1; num_reconnects++; } int KisNetClient::Reconnect() { // fprintf(stderr, "debug - knc reconnect called\n"); if (tcpcli == NULL) { return -1; } if (tcpcli->Valid() || last_disconnect == 0) { return 1; } tcpcli->KillConnection(); ostringstream osstr; if (tcpcli->ConnectSync(host, port, knc_connect_hook, this) < 0) { return 0; } return 1; } int KisNetClient::ParseData() { int len, rlen; char *buf; string strbuf; ostringstream osstr; // Scratch variables for parsing data char header[65]; // fprintf(stderr, "debug - knc::parsedata\n"); if (netclient == NULL) { // fprintf(stderr, "debug - netclient null\n"); return 0; } if (netclient->Valid() == 0) { // fprintf(stderr, "debug - netclient not valid\n"); return 0; } len = netclient->FetchReadLen(); buf = new char[len + 1]; // fprintf(stderr, "debug - knc buflen %d\n", len); fflush(stderr); if (netclient->ReadData(buf, len, &rlen) < 0) { _MSG("Kismet protocol parser failed to get data from the TCP connection", MSGFLAG_ERROR); return -1; } buf[len] = '\0'; last_read = time(0); // Parse without including partials, so we don't get a fragmented command // out of the buffer vector inptok = StrTokenize(buf, "\n", 0); delete[] buf; // Bail on no useful data if (inptok.size() < 1) { return 0; } for (unsigned int it = 0; it < inptok.size(); it++) { // No matter what we've dealt with this data block if (netclient->Valid()) netclient->MarkRead(inptok[it].length() + 1); // Pull the header out to save time -- cheaper to parse the header and // then the data than to try to parse an entire data string just to find // out what protocol we are // Throw out absurdly short lines if (inptok[it].length() < 4) continue; if (sscanf(inptok[it].c_str(), "*%64[^:]", header) < 1) { continue; } // Nuke the header off the string inptok[it].erase(0, (size_t) strlen(header) + 3); // Smarter tokenization to handle quoted field buffers vector net_toks = NetStrTokenize(inptok[it], " ", 1); // All protocols have to return something if (net_toks.size() == 0) continue; if (!strncmp(header, "KISMET", 64)) { // Decrement our configure counter configured--; // Parse the client stuff out, in a really ghetto way if (net_toks.size() >= 5) { int tint; sscanf(net_toks[1].word.c_str(), "%d", &tint); server_starttime = tint; server_name = net_toks[2].word; sscanf(net_toks[4].word.c_str(), "%d", &server_uid); _MSG("Connected to Kismet server \'" + server_name + "\'", MSGFLAG_INFO); } } else if (!strncmp(header, "TERMINATE", 64)) { osstr << "Kismet server '" << host << ":" << port << "' has " "terminated"; _MSG(osstr.str(), MSGFLAG_ERROR); netclient->KillConnection(); continue; } else if (!strncmp(header, "PROTOCOLS", 64)) { // Vectorize the protocol list vector protovec = StrTokenize(net_toks[0].word, ","); if (protovec.size() <= 0) { osstr << "Kismet server '" << host << ":" << port << "' sent a " "protocols list with nothing in it, something is broken"; _MSG(osstr.str(), MSGFLAG_ERROR); // We'll keep trying though continue; } // We expect that a protocol will never add fields once it's been // announced. If this changes, this assumption will be broken for (unsigned int pro = 0; pro < protovec.size(); pro++) { // Send a capabilities request for all of the protocols if (InjectCommand("CAPABILITY " + protovec[pro]) < 0) { osstr << "Kismet server '" << host << ":" << port << "' " "network failure while queuing a capability request"; _MSG(osstr.str(), MSGFLAG_ERROR); KillConnection(); return -1; } // Increment our configure counter configured++; } } else if (!strncmp(header, "CAPABILITY", 64)) { if (net_toks.size() != 2) { osstr << "Kismet server '" << host << ":" << port << "' " "sent a capability report without the proper fields"; _MSG(osstr.str(), MSGFLAG_ERROR); continue; } // Vectorize the field list, error check it, and make sure we're // in the list of protocols vector fieldvec = StrTokenize(net_toks[1].word, ","); if (fieldvec.size() <= 0) { osstr << "Kismet server '" << host << ":" << port << "' sent a " "protocol capability list with nothing in it, something is " "broken"; _MSG(osstr.str(), MSGFLAG_ERROR); // We'll keep trying though continue; } map >::iterator dmitr = proto_field_dmap.find(StrLower(net_toks[0].word)); // We assume protocols can't change runtime for now if (dmitr == proto_field_dmap.end()) { // Put them all in the map vector flvec; for (unsigned int fl = 0; fl < fieldvec.size(); fl++) { kcli_field_rec frec; frec.fname = StrLower(fieldvec[fl]); frec.fnum = fl; frec.usecount = 0; flvec.push_back(frec); } // Assign it proto_field_dmap[StrLower(net_toks[0].word)] = flvec; } // Decrement our configure count configured--; } else if (!strncmp(header, "ERROR", 64) && net_toks.size() >= 2) { int cmdnum; if (sscanf(net_toks[0].word.c_str(), "%d", &cmdnum) != 0) { map::iterator cbi; if ((cbi = command_cb_map.find(cmdnum)) != command_cb_map.end()) { (*(cbi->second.callback))(globalreg, this, 0, net_toks[1].word, cbi->second.auxptr); command_cb_map.erase(cbi); } } } else if (!strncmp(header, "ACK", 64)) { int cmdnum; if (sscanf(net_toks[0].word.c_str(), "%d", &cmdnum) != 0) { map::iterator cbi; if ((cbi = command_cb_map.find(cmdnum)) != command_cb_map.end()) { (*(cbi->second.callback))(globalreg, this, 1, net_toks[1].word, cbi->second.auxptr); command_cb_map.erase(cbi); } } } else if (!strncmp(header, "TIME", 64)) { // Graceful handling of junk time proto, set us to 0. int tint; if (sscanf(net_toks[0].word.c_str(), "%d", &tint) != 0) last_time = 0; else last_time = (time_t) tint; } // Call the registered handlers for this protocol, even if we handled // it internally map::iterator hi; hi = handler_cb_map.find(StrLower(header)); if (hi != handler_cb_map.end()) { for (unsigned int hx = 0; hx < hi->second.handler_vec.size(); hx++) { vector cb_toks; // Build a local vector of tokens for this protocol for (unsigned int nt = 0; nt < hi->second.handler_vec[hx]->local_fnums.size(); nt++) { // Map the absolute field number to the locally configured field // number int locfnum = hi->second.abs_to_conf_fnum_map[hi->second.handler_vec[hx]->local_fnums[nt]]; // Something has gone poorly and we've got a token in our req // that isn't in our data if (locfnum >= (int) net_toks.size()) continue; // Stack the field derived from the local field number cb_toks.push_back(net_toks[locfnum]); } CliProto_Callback cback = hi->second.handler_vec[hx]->callback; (*cback)(globalreg, inptok[it], &cb_toks, this, hi->second.handler_vec[hx]->auxptr); } } } // If we're done configuring, set it to 0 and call the configured stuff // Make sure we've been running long enough to get all the data flushed // through. This is safe to hardcode here because the TIME will always // wake us up. // fprintf(stderr, "debug - configured %d time delta %lu\n", configured, (time(0) - time_connected)); if (configured == 0 && (globalreg->timestamp.tv_sec - time_connected) > 2) { for (unsigned int x = 0; x < conf_cb_vec.size(); x++) { if (conf_cb_vec[x]->on_recon == 0 && num_reconnects != 0) continue; CliConf_Callback cback = conf_cb_vec[x]->callback; (*cback)(globalreg, this, num_reconnects, conf_cb_vec[x]->auxptr); } configured = -1; } return 1; } kismet-2013-03-R1b/Makefile.inc.in0000664000175000017500000000167712124602454016303 0ustar dragorndragornINSTGRP ?= "@instgrp@" MANGRP ?= "@mangrp@" INSTUSR ?= "root" ZAURUS = @zaurus@ PCAPLNK = @pcaplnk@ THREADL = @threadlib@ BLDHOME = @srcdir@ CXX = @CXX@ CC = @CC@ LD = @CXX@ REALLD = @LD@ LDFLAGS = @LDFLAGS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBS = @LIBS@ CLIBS = @CLIBS@ CXXLIBS = @CXXLIBS@ KSLIBS = @KSLIBS@ CFLAGS = @CPPFLAGS@ CLIENTLIBS = @CLIENTCLIBS@ CAPLIBS = @caplibs@ CLIENTFLAGS = @CLIENTCFLAGS@ CXXFLAGS = -Wall @CXXFLAGS@ CPPFLAGS = @CPPFLAGS@ SUIDGROUP = @suidgroup@ prefix = @prefix@ exec_prefix = @exec_prefix@ plugindir = @libdir@/kismet ETC = ${DESTDIR}@sysconfdir@ BIN = ${DESTDIR}@bindir@ SHARE = ${DESTDIR}@datadir@/kismet/ MAN = ${DESTDIR}@mandir@ LIB = ${DESTDIR}@libdir@ WAV = ${DESTDIR}@datadir@/kismet/wav/ PLUGINLDFLAGS = @PLUGINLDFLAGS@ @LDFLAGS@ kismet-2013-03-R1b/packetsourcetracker.cc0000664000175000017500000025136212124602454020037 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include "util.h" #include "kis_netframe.h" #include "packetsourcetracker.h" #include "packetsource.h" #include "configfile.h" #include "getopt.h" // Broken source assigned to sources which utterly fail to parse during startup, // with the goal of setting the warning so that it'll pop in the UI properly. // Should only ever be used as a protosource class PacketSource_Broken : public KisPacketSource { public: PacketSource_Broken() { } PacketSource_Broken(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { error = 1; } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return NULL; } virtual void SetWarning(string in_warning) { warning = in_warning; } virtual int AutotypeProbe(string in_device) { return 0; } virtual int RegisterSources(Packetsourcetracker *tracker) { return 0; } PacketSource_Broken(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { } virtual ~PacketSource_Broken() { } virtual int EnableMonitor() { return 0; } virtual int DisableMonitor() { return 0; } virtual int FetchChannelCapable() { return 0; } virtual int SetChannel(unsigned int in_ch) { return 0; } virtual int ChildIPCControl() { return 0; } virtual int OpenSource() { return 0; } virtual int CloseSource() { return 0; } virtual int FetchDescriptor() { return -1; } virtual int Poll() { return 0; } virtual int FetchHardwareChannel() { return 0; } virtual int ManglePacket(kis_packet *packet, kis_datachunk *linkchunk) { return 0; } protected: virtual int DatalinkType() { return 0; } virtual void FetchRadioData(kis_packet *in_packet) { } }; enum SOURCE_fields { SOURCE_interface, SOURCE_type, SOURCE_username, SOURCE_channel, SOURCE_uuid, SOURCE_packets, SOURCE_hop, SOURCE_velocity, SOURCE_dwell, SOURCE_hop_tv_sec, SOURCE_hop_tv_usec, SOURCE_channellist, SOURCE_error, SOURCE_warning, SOURCE_maxfield }; const char *SOURCE_fields_text[] = { "interface", "type", "username", "channel", "uuid", "packets", "hop", "velocity", "dwell", "hop_time_sec", "hop_time_usec", "channellist", "error", "warning", NULL }; enum PROTOSOURCE_fields { PROTOSOURCE_type, PROTOSOURCE_root, PROTOSOURCE_defaultchanlist, PROTOSOURCE_maxfield }; const char *PROTOSOURCE_fields_text[] = { "type", "root", "defaultchannellist", NULL }; void Protocol_SOURCE_enable(PROTO_ENABLE_PARMS) { ((Packetsourcetracker *) data)->BlitSources(in_fd); } void Protocol_PROTOSOURCE_enable(PROTO_ENABLE_PARMS) { ((Packetsourcetracker *) data)->BlitProtoSources(in_fd); } int Protocol_SOURCE(PROTO_PARMS) { pst_packetsource *psrc = (pst_packetsource *) data; ostringstream osstr; string w; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= SOURCE_maxfield) { out_string += "Unknown field requested"; return -1; } osstr.str(""); if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case SOURCE_interface: cache->Cache(fnum, psrc->interface); break; case SOURCE_type: if (psrc->strong_source != NULL) cache->Cache(fnum, psrc->strong_source->FetchType()); else cache->Cache(fnum, "N/A"); break; case SOURCE_username: if (psrc->strong_source != NULL) cache->Cache(fnum, psrc->strong_source->FetchName()); else cache->Cache(fnum, "N/A"); break; case SOURCE_channel: osstr << psrc->channel; cache->Cache(fnum, osstr.str()); break; case SOURCE_uuid: if (psrc->strong_source != NULL) cache->Cache(fnum, psrc->strong_source->FetchUUID().UUID2String()); else cache->Cache(fnum, "00000000-0000-0000-0000-000000000000"); break; case SOURCE_packets: if (psrc->strong_source != NULL) { osstr << psrc->strong_source->FetchNumPackets(); cache->Cache(fnum, osstr.str()); } else { cache->Cache(fnum, "0"); } break; case SOURCE_hop: osstr << psrc->channel_hop; cache->Cache(fnum, osstr.str()); break; case SOURCE_velocity: osstr << psrc->channel_rate; cache->Cache(fnum, osstr.str()); break; case SOURCE_dwell: osstr << psrc->channel_dwell; cache->Cache(fnum, osstr.str()); break; case SOURCE_hop_tv_sec: osstr << psrc->tm_hop_time.tv_sec; cache->Cache(fnum, osstr.str()); break; case SOURCE_hop_tv_usec: osstr << psrc->tm_hop_time.tv_usec; cache->Cache(fnum, osstr.str()); break; case SOURCE_error: if (psrc->error || (psrc->strong_source != NULL && psrc->strong_source->FetchError())) osstr << "1"; else osstr << "0"; cache->Cache(fnum, osstr.str()); break; case SOURCE_warning: if (psrc->warning != "") { w = psrc->warning; } else if (psrc->strong_source != NULL) { w = psrc->strong_source->FetchWarning(); } else if (psrc->proto_source != NULL && psrc->proto_source->weak_source != NULL) { psrc->proto_source->weak_source->FetchWarning(); } else { w = ""; } cache->Cache(fnum, string("\001") + w + string("\001")); break; case SOURCE_channellist: if (psrc->channel_ptr == NULL) { cache->Cache(fnum, IntToString(psrc->channel)); } else { for (unsigned int c = 0; c < psrc->channel_ptr->channel_vec.size(); c++) { if (psrc->channel_ptr->channel_vec[c].range == 0) { osstr << psrc->channel_ptr->channel_vec[c].u.chan_t.channel; if (psrc->channel_ptr->channel_vec[c].u.chan_t.dwell > 1) osstr << ":" << psrc->channel_ptr->channel_vec[c].u.chan_t.dwell; } else { osstr << "range-" << psrc->channel_ptr->channel_vec[c].u.range_t.start << "-" << psrc->channel_ptr->channel_vec[c].u.range_t.end << "-" << psrc->channel_ptr->channel_vec[c].u.range_t.width << "-" << psrc->channel_ptr->channel_vec[c].u.range_t.iter; } if (c != psrc->channel_ptr->channel_vec.size() - 1) osstr << ","; } cache->Cache(fnum, osstr.str()); } break; } out_string += cache->GetCache(fnum) + " "; } return 1; } // IPC hooks int pst_ipc_add_source(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_add)) return 0; ((Packetsourcetracker *) auxptr)->IpcAddPacketsource((ipc_source_add *) data); return 1; } int pst_ipc_add_channellist(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_add_chanlist)) return 0; ((Packetsourcetracker *) auxptr)->IpcAddChannelList( (ipc_source_add_chanlist *) data); return 1; } int pst_ipc_set_channel(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_chanset)) return 0; ((Packetsourcetracker *) auxptr)->IpcChannelSet((ipc_source_chanset *) data); return 1; } int pst_ipc_sync_complete(IPC_CMD_PARMS) { if (parent) return 0; ((Packetsourcetracker *) auxptr)->RegisterIPC(NULL, 0); return 1; } int pst_ipc_rx_stats(IPC_CMD_PARMS) { if (!parent) return 0; if (len < (int) sizeof(ipc_source_report)) return 0; ((Packetsourcetracker *) auxptr)->IpcSourceReport((ipc_source_report *) data); return 1; } int pst_ipc_run(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_run)) return 0; ((Packetsourcetracker *) auxptr)->IpcSourceRun((ipc_source_run *) data); return 1; } int pst_ipc_stop(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_run)) return 0; ((Packetsourcetracker *) auxptr)->IpcSourceRun((ipc_source_run *) data); return 1; } int pst_ipc_remove(IPC_CMD_PARMS) { if (parent) return 0; if (len < (int) sizeof(ipc_source_remove)) return 0; ((Packetsourcetracker *) auxptr)->IpcSourceRemove((ipc_source_remove *) data); return 1; } int pst_ipc_packet(IPC_CMD_PARMS) { if (!parent) return 0; if (len < (int) sizeof(ipc_source_packet)) return 0; ((Packetsourcetracker *) auxptr)->IpcPacket((ipc_source_packet *) data); return 1; } int pst_ipc_chanreport(IPC_CMD_PARMS) { if (!parent) return 0; if (len < (int) sizeof(ipc_source_chanreport)) return 0; ((Packetsourcetracker *) auxptr)->IpcChannelReport((ipc_source_chanreport *) data); return 1; } int pst_channeltimer(TIMEEVENT_PARMS) { ((Packetsourcetracker *) parm)->ChannelTimer(); return 1; } int pst_opentimer(TIMEEVENT_PARMS) { ((Packetsourcetracker *) parm)->OpenTimer(); return 1; } int pst_sourceprototimer(TIMEEVENT_PARMS) { ((Packetsourcetracker *) parm)->BlitSources(-1); return 1; } int pst_chain_hook(CHAINCALL_PARMS) { ((Packetsourcetracker *) auxdata)->ChainHandler(in_pack); return 1; } int pst_cmd_ADDSOURCE(CLIENT_PARMS) { return ((Packetsourcetracker *) auxptr)->cmd_ADDSOURCE(in_clid, framework, errstr, cmdline, parsedcmdline); } int pst_cmd_RESTARTSOURCE(CLIENT_PARMS) { return ((Packetsourcetracker *) auxptr)->cmd_RESTARTSOURCE(in_clid, framework, errstr, cmdline, parsedcmdline); } int pst_cmd_DELSOURCE(CLIENT_PARMS) { return ((Packetsourcetracker *) auxptr)->cmd_DELSOURCE(in_clid, framework, errstr, cmdline, parsedcmdline); } int pst_cmd_HOPSOURCE(CLIENT_PARMS) { return ((Packetsourcetracker *) auxptr)->cmd_HOPSOURCE(in_clid, framework, errstr, cmdline, parsedcmdline); } int pst_cmd_CHANLIST(CLIENT_PARMS) { return ((Packetsourcetracker *) auxptr)->cmd_CHANLIST(in_clid, framework, errstr, cmdline, parsedcmdline); } void Packetsourcetracker::Usage(char *name) { printf(" *** Packet Capture Source Options ***\n"); printf(" -c, --capture-source Specify a new packet capture source\n" " (Identical syntax to the config file)\n" " -C, --enable-capture-sources Enable capture sources (comma-separated\n" " list of names or interfaces)\n"); } Packetsourcetracker::Packetsourcetracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; timer_counter = 0; if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: Packetsourcetracker called before " "kisnetframework\n"); exit(1); } if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: Packetsourcetracker called before timetracker\n"); exit(1); } if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Packetsourcetracker called before packetchain\n"); exit(1); } // Register our packet components // back-refer to the capsource so we can get names and parameters _PCM(PACK_COMP_KISCAPSRC) = globalreg->packetchain->RegisterPacketComponent("KISCAPSRC"); // Basic packet chunks everyone needs - while it doesn't necessarily // make sense to do this here, it makes as much sense as anywhere else _PCM(PACK_COMP_RADIODATA) = globalreg->packetchain->RegisterPacketComponent("RADIODATA"); _PCM(PACK_COMP_LINKFRAME) = globalreg->packetchain->RegisterPacketComponent("LINKFRAME"); _PCM(PACK_COMP_80211FRAME) = globalreg->packetchain->RegisterPacketComponent("80211FRAME"); _PCM(PACK_COMP_FCSBYTES) = globalreg->packetchain->RegisterPacketComponent("FCSBYTES"); globalreg->packetchain->RegisterHandler(&pst_chain_hook, this, CHAINPOS_POSTCAP, -100); // Register the packetsourcetracker as a pollable subsystem globalreg->RegisterPollableSubsys(this); // Set up the base source IDs - 0 indicates error next_source_id = 1; next_channel_id = 1; running_as_ipc = 0; rootipc = NULL; channel_time_id = globalreg->timetracker->RegisterTimer(1, NULL, 1, &pst_channeltimer, this); open_time_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 10, NULL, 1, &pst_opentimer, this); source_protoref = globalreg->kisnetserver->RegisterProtocol("SOURCE", 0, 1, SOURCE_fields_text, &Protocol_SOURCE, &Protocol_SOURCE_enable, this); cmd_addsource_id = globalreg->kisnetserver->RegisterClientCommand("ADDSOURCE", &pst_cmd_ADDSOURCE, (void *) this); cmd_delsource_id = globalreg->kisnetserver->RegisterClientCommand("DELSOURCE", &pst_cmd_DELSOURCE, (void *) this); cmd_restartsource_id = globalreg->kisnetserver->RegisterClientCommand("RESTARTSOURCE", &pst_cmd_RESTARTSOURCE, (void *) this); cmd_hopsource_id = globalreg->kisnetserver->RegisterClientCommand("HOPSOURCE", &pst_cmd_HOPSOURCE, (void *) this); cmd_channellist_id = globalreg->kisnetserver->RegisterClientCommand("CHANSOURCE", &pst_cmd_CHANLIST, (void *) this); proto_source_time_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &pst_sourceprototimer, this); } Packetsourcetracker::~Packetsourcetracker() { StopSource(0); globalreg->RemovePollableSubsys(this); globalreg->timetracker->RemoveTimer(channel_time_id); if (globalreg->packetchain != NULL) globalreg->packetchain->RemoveHandler(&pst_chain_hook, CHAINPOS_POSTCAP); // We could delete the card stuff but we're only ever called during // shutdown and fail, so who cares. } void Packetsourcetracker::RegisterIPC(IPCRemote *in_ipc, int in_as_ipc) { // Ignore params if we're called with NULL if (in_ipc != NULL) { rootipc = in_ipc; running_as_ipc = in_as_ipc; sync_ipc_id = rootipc->RegisterIPCCmd(*pst_ipc_sync_complete, NULL, this, "SYNCCOMPLETE"); } // Register on both sides of the IPC so the negotiation works properly source_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_add_source, NULL, this, "SOURCEADD"); channellist_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_add_channellist, NULL, this, "SOURCEADDCHAN"); channel_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_set_channel, NULL, this, "SOURCESETCHAN"); report_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_rx_stats, NULL, this, "SOURCEREPORT"); run_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_run, NULL, this, "SOURCERUN"); stop_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_stop, NULL, this, "SOURCESTOP"); packet_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_packet, NULL, this, "SOURCEFRAME"); remove_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_remove, NULL, this, "SOURCEREMOVE"); chanreport_ipc_id = rootipc->RegisterIPCCmd(&pst_ipc_chanreport, NULL, this, "SOURCECHANREPORT"); } // Simple aggregate of all our pollable sources. Sources linked via IPC will // be ignored (they'll return -1 for the descriptor) int Packetsourcetracker::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { // don't merge during shutdown if (globalreg->spindown) return in_max_fd; int max = in_max_fd; for (map::const_iterator x = packetsource_map.begin(); x != packetsource_map.end(); ++x) { if (x->second->strong_source == NULL || x->second->error == 1) continue; int capd = x->second->strong_source->FetchDescriptor(); if (capd < 0) continue; FD_SET(capd, out_rset); if (capd > max) max = capd; } return max; } // Kick a packet source poll event int Packetsourcetracker::Poll(fd_set& in_rset, fd_set& in_wset) { if (globalreg->spindown) return 0; for (map::iterator x = packetsource_map.begin(); x != packetsource_map.end(); ++x) { if (x->second->strong_source == NULL) continue; if (x->second->error) continue; int capd = x->second->strong_source->FetchDescriptor(); if (capd >= 0 && FD_ISSET(capd, &in_rset)) { if (x->second->strong_source->Poll() <= 0) { x->second->zeropoll++; } else { x->second->zeropoll = 0; } } if (x->second->zeropoll > 100) { _MSG("Packet source '" + x->second->strong_source->FetchName() + "' is no longer returning any data when polled, it has " "probably been disconnected, and will be closed.", MSGFLAG_ERROR); if (x->second->reopen) _MSG("Kismet will attempt to re-open packet source '" + x->second->strong_source->FetchName() + "' in 10 seconds", MSGFLAG_ERROR); x->second->strong_source->CloseSource(); x->second->error = 1; SendIPCReport(x->second); x->second->zeropoll = 0; } } return 1; } int Packetsourcetracker::RegisterPacketSource(KisPacketSource *in_weak) { return in_weak->RegisterSources(this); } int Packetsourcetracker::RegisterPacketProto(string in_type, KisPacketSource *in_weak, string in_defaultchan, int in_root) { pst_protosource *proto; for (unsigned int x = 0; x != protosource_vec.size(); x++) { if (protosource_vec[x]->type == StrLower(in_type)) { _MSG("Packet source type '" + in_type + "' already registered, ignoring.", MSGFLAG_ERROR); return 0; } } proto = new pst_protosource; proto->type = in_type; proto->weak_source = in_weak; proto->default_channelset = in_defaultchan; proto->require_root = in_root; protosource_vec.push_back(proto); return 1; } uint16_t Packetsourcetracker::AddChannelList(string in_chanlist) { vector cvec; vector tvec; string name; size_t pos = in_chanlist.find(":"); pst_channellist *chlist; vector chvec; pst_channel ch; if (in_chanlist.length() == 0 || pos == string::npos) { _MSG("Invalid channel list, expected 'channellist=:{[:],}+'", MSGFLAG_ERROR); return 0; } name = in_chanlist.substr(0, pos); cvec = StrTokenize(in_chanlist.substr(pos + 1, in_chanlist.size() - pos - 1), ","); if (cvec.size() == 0) { _MSG("Invalid channel list, expected 'channellist=:{[:],}+'", MSGFLAG_ERROR); return 0; } for (unsigned int x = 0; x < cvec.size(); x++) { tvec = StrTokenize(cvec[x], ":"); if (tvec.size() >= 1) { if (sscanf(tvec[0].c_str(), "%u", &ch.u.chan_t.channel) == 1) { ch.u.chan_t.dwell = 1; ch.range = 0; } else if (sscanf(tvec[0].c_str(), "range-%u-%u-%u-%u", &ch.u.range_t.start, &ch.u.range_t.end, &ch.u.range_t.width, &ch.u.range_t.iter) == 4) { ch.range = 1; } else { _MSG("Invalid channel in channel list '" + name + "', expected " "channel number, mhz frequency, or range definition", MSGFLAG_ERROR); return 0; } } if (tvec.size() >= 2 && ch.range == 0) { if (sscanf(tvec[1].c_str(), "%u", &ch.u.chan_t.dwell) != 1) { _MSG("Invalid dwell time in channel list '" + name + "', expected " "a dwell time as a number.", MSGFLAG_ERROR); return 0; } if (ch.u.chan_t.dwell > 6) { _MSG("Dwell time in channel list '" + name + "' is over 6 periods, " "this might indicate a typo in the channel config as it is longer " "than expected.", MSGFLAG_ERROR); } } chvec.push_back(ch); } chlist = new pst_channellist; chlist->auto_generated = 0; chlist->channel_id = next_channel_id; chlist->name = StrLower(name); chlist->channel_vec = chvec; next_channel_id++; channellist_map[chlist->channel_id] = chlist; SendIPCChannellist(chlist); return chlist->channel_id; } uint16_t Packetsourcetracker::GenChannelList(vector in_channellist) { unsigned int compared; pst_channellist *chlist; pst_channel pch; if (in_channellist.size() >= IPC_SOURCE_MAX_CHANS || in_channellist.size() == 0) { return 0; } // Look for the channels in one of the existing channel vectors (must be // an autocreated list to share an ID with another autocreated list). for (map::iterator chi = channellist_map.begin(); chi != channellist_map.end(); ++chi) { if (chi->second->auto_generated == 0) continue; if (chi->second->channel_vec.size() != in_channellist.size()) continue; compared = 0; /* Nasty slow compare but we only do it during startup on a limited number * of channels anyhow */ for (unsigned int x = 0; x < chi->second->channel_vec.size(); x++) { for (unsigned int y = 0; y < in_channellist.size(); y++) { if (chi->second->channel_vec[x].range) continue; if (chi->second->channel_vec[x].u.chan_t.channel == in_channellist[y]) compared++; } } if (compared == in_channellist.size()) return chi->first; } chlist = new pst_channellist; chlist->auto_generated = 1; chlist->channel_id = next_channel_id; chlist->name = "auto" + IntToString(next_channel_id); next_channel_id++; channellist_map[chlist->channel_id] = chlist; pch.range = 0; pch.u.chan_t.dwell = 1; unsigned int c = 0, l = 0; for (unsigned int x = 0; c < in_channellist.size(); x+=4, c++) { if (x >= in_channellist.size()) x = ++l; pch.u.chan_t.channel = in_channellist[x]; chlist->channel_vec.push_back(pch); } SendIPCChannellist(chlist); return chlist->channel_id; } int Packetsourcetracker::AddPacketSource(string in_source, KisPacketSource *in_strong, uint16_t *source_id) { string interface; string type; string chanlistname; vector options; size_t pos = in_source.find(":"); pst_packetsource *pstsource = NULL; int found = 0; if (pos == string::npos) { interface = in_source; } else { interface = in_source.substr(0, pos); if (StringToOpts(in_source.substr(pos + 1, in_source.size() - pos - 1), ",", &options) < 0) { _MSG("Invalid options list for source '" + interface + "', expected " "ncsource=interface[,option=value]+", MSGFLAG_ERROR); return -1; } } pstsource = new pst_packetsource; pstsource->interface = interface; if (in_strong != NULL) pstsource->local_only = 1; else pstsource->local_only = 0; pstsource->sourceline = in_source; pstsource->strong_source = in_strong; pstsource->proto_source = NULL; // Set to an undefined status first pstsource->channel = 0; pstsource->channel_list = 0; pstsource->channel_ptr = NULL; pstsource->channel_hop = -1; pstsource->channel_position = 0; pstsource->range_position = 0; pstsource->channel_dwell = -1; pstsource->channel_rate = -1; pstsource->channel_split = 1; pstsource->rate_timer = 0; pstsource->dwell_timer = 0; pstsource->tm_hop_start.tv_sec = 0; pstsource->tm_hop_start.tv_usec = 0; pstsource->tm_hop_time.tv_sec = 0; pstsource->tm_hop_time.tv_usec = 0; pstsource->consec_channel_err = 0; pstsource->error = 0; pstsource->reopen = 1; pstsource->zeropoll = 0; string name = StrLower(FetchOpt("name", &options)); if (name == "") name = interface; int matched = 0; if (named_vec.size() == 0) matched = 1; for (unsigned int y = 0; y < named_vec.size(); y++) { if (StrLower(named_vec[y]) == name) { matched = 1; break; } } if (matched == 0 && pstsource->strong_source == NULL) { _MSG("Source '" + name + "' not in enable_sources list, will not be " "enabled.", MSGFLAG_INFO); delete pstsource; return 0; } // Try to map the type when they tell us what it is if ((type = FetchOpt("type", &options)) != "" && type != "auto" && pstsource->strong_source == NULL) { found = 0; for (unsigned int x = 0; x < protosource_vec.size(); x++) { if (protosource_vec[x]->type == StrLower(type)) { found = 1; pstsource->proto_source = protosource_vec[x]; break; } } if (found == 0) { _MSG("Invalid type '" + type + "'; Unknown, or support was not compiled " "into this build of Kismet, check the output of the 'configure' " "script if you compiled Kismet yourself.", MSGFLAG_ERROR); delete pstsource; return -1; } } // Try to figure out the auto types if (pstsource->strong_source == NULL && (type == "auto" || type == "")) { for (unsigned int x = 0; x < protosource_vec.size(); x++) { if (protosource_vec[x]->weak_source->AutotypeProbe(interface) != 0) { pstsource->proto_source = protosource_vec[x]; type = pstsource->proto_source->weak_source->FetchType(); _MSG("Matched source type '" + type + "' for auto-type source '" + interface + "'", MSGFLAG_INFO); ReplaceAllOpts("type", type, &options); break; } } if (type == "" || type == "auto") { _MSG("Failed to find a type for auto-type source '" + interface + "', " "you will have to tell Kismet what it is by adding a " "type=[card type] to the ncsource config", MSGFLAG_PRINTERROR); _MSG("It is possible that the device for interface '" + interface + "' " "is not active or was not plugged in. Kismet will ignore this " "interface, you may re-add it later.", MSGFLAG_PRINTERROR); pst_protosource *broken_weak = new pst_protosource; broken_weak->type = "BROKEN"; broken_weak->require_root = 0; broken_weak->weak_source = new PacketSource_Broken(globalreg); ((PacketSource_Broken *) broken_weak->weak_source)->SetWarning( "Couldn't auto-detect a driver for interface '" + interface + "'. " "There may be a problem with the device (such as it not existing) or it " "may use one of the drivers which cannot be auto-detected. See the " "README section 'Caveats and quirks for specific drivers' to learn how " "to configure the specific driver."); pstsource->proto_source = broken_weak; // Push it into the vec so that we pop a warning on the client pstsource->error = 1; pstsource->reopen = 0; pstsource->strong_source = NULL; pstsource->source_id = next_source_id; packetsource_map[pstsource->source_id] = pstsource; packetsource_vec.push_back(pstsource); next_source_id++; return 0; } } // Push the option set if we were given a strong source if (in_strong != NULL) pstsource->strong_source->ParseOptions(&options); // Resolve the channel list chanlistname = FetchOpt("channellist", &options); if (chanlistname == "" && in_strong == NULL) { vector chvec; if (pstsource->proto_source != NULL) chvec = pstsource->proto_source->weak_source->FetchSupportedChannels(interface); else if (pstsource->strong_source != NULL) chvec = pstsource->strong_source->FetchSupportedChannels(interface); uint16_t chid = 0; string chlist; if (chvec.size() > 0) chid = GenChannelList(chvec); if (chid <= 0 && pstsource->proto_source != NULL) { chanlistname = pstsource->proto_source->default_channelset; _MSG("Using default channel list '" + chanlistname + "' on source '" + name + "'", MSGFLAG_INFO); } else { string dmod = ""; for (unsigned int z = 0; chvec.size() > 0 && z < chvec.size() - 1; z++) { // Another stupidly inefficient method but it happens very rarely for (unsigned int y = 0; y < preferred_channels.size(); y++) { if (preferred_channels[y] == chvec[z]) { dmod = ":3"; break; } } chlist += (IntToString(chvec[z]) + dmod + ","); dmod = ""; } for (unsigned int y = 0; y < preferred_channels.size(); y++) { if (chvec.size() > 0 && preferred_channels[y] == chvec[chvec.size() - 1]) { dmod = ":3"; break; } } if (chvec.size() > 0) chlist += (IntToString(chvec[chvec.size() - 1]) + dmod); chanlistname = channellist_map[chid]->name; _MSG("Using hardware channel list " + chlist + ", " + IntToString(chvec.size()) + " channels on source " + name, MSGFLAG_INFO); } } else { _MSG("Using channel list '" + chanlistname + "' on source '" + name + "' instead of the default", MSGFLAG_INFO); } found = 0; for (map::iterator x = channellist_map.begin(); x != channellist_map.end(); ++x) { if (StrLower(chanlistname) == x->second->name) { found = 1; pstsource->channel_list = x->first; pstsource->channel_ptr = x->second; break; } } if (found == 0 && chanlistname != "n/a") { _MSG("Missing channel list '" + chanlistname + "' for source '" + interface + "'. Make sure your kismet.conf file contains a " "channellist=" + chanlistname + " line", MSGFLAG_ERROR); return -1; } // Do the initial build of a strong source now that we know the type if (pstsource->strong_source == NULL) pstsource->strong_source = pstsource->proto_source->weak_source->CreateSource(globalreg, interface, &options); _MSG("Created source " + interface + " with UUID " + pstsource->strong_source->FetchUUID().UUID2String(), MSGFLAG_INFO); // Figure out stuff we need the source definition for, after we've errored out // on the common failures if (pstsource->strong_source->FetchChannelCapable() == 0) { _MSG("Disabling channel hopping on source '" + name + "' because " "it is not capable of setting the channel.", MSGFLAG_INFO); pstsource->channel_hop = 0; } else { pstsource->channel_hop = default_channel_rate; pstsource->channel_dwell = default_channel_dwell; if (FetchOpt("channel", &options) != "") { _MSG("Source '" + name + "' ignoring channel= in the source " "options because it is set to hop, specify hop=false to lock " "to a specific channel.", MSGFLAG_INFO); } } // if (FetchOpt("hop", &options) != "true" && FetchOpt("hop", &options) != "") { if (FetchOptBoolean("hop", &options, 1) == 0) { _MSG("Disabling channel hopping on source '" + name + "' because the " "source options include hop=false", MSGFLAG_INFO); pstsource->channel_hop = 0; if (FetchOpt("channel", &options) == "") { _MSG("Source '" + interface + "' has no channel= in the source " "options and has channel hopping disabled, it will be left on " "whatever channel it is currently on", MSGFLAG_INFO); } else { if (sscanf(FetchOpt("channel", &options).c_str(), "%hu", &(pstsource->channel)) != 1) { _MSG("Invalid channel for source '" + interface + "', expected " "channel number or frequency", MSGFLAG_ERROR); _MSG("Kismet will ignore the source '" + interface + "' due to " "unrecoverable errors during setup, you may add it again " "later once these errors are resolved", MSGFLAG_PRINTERROR); delete pstsource; return 0; } _MSG("Source '" + interface + "' will be locked to channel " + FetchOpt("channel", &options), MSGFLAG_INFO); } } if (FetchOpt("hop", &options) == "" && FetchOpt("channel", &options) != "" && pstsource->channel_hop != 0) { _MSG("Ignoring channel= option for source '" + interface + "' because " "the source is channel hopping. Set hop=false on the source options " "to disable hopping and lock to the specified channel", MSGFLAG_INFO); } if (FetchOpt("dwell", &options) != "" && pstsource->channel_hop) { if (sscanf(FetchOpt("dwell", &options).c_str(), "%d", &pstsource->channel_dwell) != 1) { _MSG("Invalid time for source '" + interface + "' dwell time, expected " "time in seconds to dwell on a channel", MSGFLAG_ERROR); _MSG("Kismet will ignore the source '" + interface + "' due to " "unrecoverable errors during setup, you may add it again " "later once these errors are resolved", MSGFLAG_PRINTERROR); delete pstsource; return 0; } _MSG("Source '" + interface + "' will dwell on each channel " + FetchOpt("dwell", &options) + " second(s)", MSGFLAG_INFO); } if (FetchOpt("velocity", &options) != "" && pstsource->channel_hop) { if (sscanf(FetchOpt("velocity", &options).c_str(), "%d", &pstsource->channel_rate) != 1) { _MSG("Invalid time for source '" + interface + "' hop rate, expected " "velocity in channels per second to (attempt) hopping", MSGFLAG_ERROR); delete pstsource; return 0; } if (pstsource->channel_dwell > 0) { _MSG("Conflicting options for source '" + interface + "', cannot specify " "both dwell (seconds spend on channel) and rate (channels per second " "hop rate) for the same source, dwell will be ignored and hop rate " "will be used.", MSGFLAG_ERROR); pstsource->channel_dwell = 0; } if (pstsource->channel_rate > SERVER_TIMESLICES_SEC) { ostringstream osstr; osstr << "Channel rate for source '" << interface << "' specified as " << pstsource->channel_rate << " but Kismet only allows a maximum of " << SERVER_TIMESLICES_SEC << " channel hops per second, packet rate " "will be fixed to the maximum supported rate."; _MSG(osstr.str(), MSGFLAG_ERROR); pstsource->channel_rate = SERVER_TIMESLICES_SEC; } if (pstsource->channel_rate > pstsource->strong_source->FetchChannelMaxVelocity()) { _MSG("Channel rate for source '" + interface + "' specified as " + IntToString(pstsource->channel_rate) + " is greater than the " "maximum supported hop rate on that interface, and will be " "limited to the maximum rate, " + IntToString(pstsource->strong_source->FetchChannelMaxVelocity()), MSGFLAG_INFO); pstsource->channel_rate = pstsource->strong_source->FetchChannelMaxVelocity(); } _MSG("Source '" + interface + "' will attempt to hop at " + IntToString(pstsource->channel_rate) + " channel(s) per second.", MSGFLAG_INFO); } // Assume the defaults if (pstsource->channel_dwell < 0) pstsource->channel_dwell = default_channel_dwell; if (pstsource->channel_rate < 0) pstsource->channel_rate = default_channel_rate; if (FetchOpt("split", &options) != "" && pstsource->channel_hop) { // if (FetchOpt("split", &options) != "true") { if (FetchOptBoolean("split", &options, 0)) { _MSG("Disabling channel list splitting on interface '" + interface + "' " "because split=false was in the source options. This source will " "not balance channel offsets with other sources using the same " "channel list and will instead hop normally", MSGFLAG_INFO); pstsource->channel_split = 0; } } // if (FetchOpt("retry", &options) == "" || FetchOpt("retry", &options) == "true") { if (FetchOptBoolean("retry", &options, 1)) { _MSG("Will attempt to reopen on source '" + name + "' if there are errors", MSGFLAG_INFO); pstsource->reopen = 1; } else { _MSG("Will not attempt to reopen source '" + interface + "' if there are errors", MSGFLAG_INFO); pstsource->reopen = 0; } // Add the created strong source to our list pstsource->source_id = next_source_id; packetsource_map[pstsource->source_id] = pstsource; packetsource_vec.push_back(pstsource); next_source_id++; if (pstsource->proto_source != NULL && pstsource->proto_source->require_root) SendIPCSourceAdd(pstsource); // Send a notify to all the registered callbacks for (unsigned int x = 0; x < cb_vec.size(); x++) { (*(cb_vec[x]->cb))(globalreg, pstsource, SOURCEACT_ADDSOURCE, 0, cb_vec[x]->auxdata); } *source_id = pstsource->source_id; return 1; } int Packetsourcetracker::LoadConfiguration() { vector src_input_vec; vector chan_vec; string named_sources; int option_idx = 0; static struct option packetsource_long_options[] = { { "capture-source", required_argument, 0, 'c' }, { "enable-capture-source", required_argument, 0, 'C' }, { 0, 0, 0, 0 } }; default_channel_rate = 5; default_channel_dwell = 0; if (globalreg->kismet_config == NULL) { _MSG("Packetsourcetracker LoadConfiguration called before kismet_config " "loaded", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Parse the default velocity and dwell if (globalreg->kismet_config->FetchOpt("channelvelocity") != "" && sscanf(globalreg->kismet_config->FetchOpt("channelvelocity").c_str(), "%d", &default_channel_rate) != 1) { _MSG("Invalid channelvelocity=... in the Kismet config file, expected " "a number of channels per second to attempt to hop.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if (globalreg->kismet_config->FetchOpt("channeldwell") != "" && sscanf(globalreg->kismet_config->FetchOpt("channeldwell").c_str(), "%d", &default_channel_dwell) != 1) { _MSG("Invalid channeldwell=... in the Kismet config file, expected " "a number of seconds per channel to wait", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } vector tokvec = StrTokenize(globalreg->kismet_config->FetchOpt("preferredchannels"), ","); for (unsigned int x = 0; x < tokvec.size(); x++) { unsigned int tu; if (sscanf(tokvec[x].c_str(), "%u", &tu) != 1) { _MSG("Invalid channel in preferredchannels= in the Kismet config file, " "expected a channel number.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } preferred_channels.push_back(tu); } if (preferred_channels.size() > 0) { string m = "Kismet will spend extra time on channels "; for (unsigned int x = 0; x < preferred_channels.size(); x++) { m += IntToString((int) preferred_channels[x]); if (x != preferred_channels.size() - 1) m += ","; } _MSG(m, MSGFLAG_INFO); } if (default_channel_dwell != 0) { _MSG("Kismet will dwell on each channel for " + globalreg->kismet_config->FetchOpt("channeldwell") + " seconds " "unless overridden by source-specific options.", MSGFLAG_INFO); } else if (default_channel_rate != 0) { _MSG("Kismet will attempt to hop channels at " + globalreg->kismet_config->FetchOpt("channelvelocity") + " channels " "per second unless overridden by source-specific options", MSGFLAG_INFO); } else { _MSG("No default channel dwell or hop rates specified, Kismet will attempt " "to hop 5 channels per second.", MSGFLAG_INFO); default_channel_rate = 5; } // Hack the extern getopt index optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-c:C:", packetsource_long_options, &option_idx); if (r < 0) break; switch (r) { case 'C': named_sources = string(optarg); break; case 'c': src_input_vec.push_back(string(optarg)); break; } } // If we didn't get any command line options, pull both from the config // file options if (named_sources.length() == 0 && src_input_vec.size() == 0) { _MSG("No specific sources named on the command line, sources will be read " "from kismet.conf", MSGFLAG_INFO); named_sources = globalreg->kismet_config->FetchOpt("enablesources"); src_input_vec = globalreg->kismet_config->FetchOptVec("ncsource"); } else if (src_input_vec.size() == 0) { _MSG("Reading sources from kismet.conf but only enabling sources specified " "on the command line", MSGFLAG_INFO); src_input_vec = globalreg->kismet_config->FetchOptVec("ncsource"); } if (src_input_vec.size() == 0) { _MSG("No sources found - Remember, Kismet recently changed the format of " "sources, and to make it easier to identify old configs, sources are " "now identified by the 'ncsource=...' config file line. Kismet CAN " "be started with no predefined sources, however MAKE SURE this is " "what you wanted!", MSGFLAG_ERROR); } named_vec = StrTokenize(named_sources, ","); // Fetch the channel lists and add them chan_vec = globalreg->kismet_config->FetchOptVec("channellist"); if (chan_vec.size() == 0) { if (chan_vec.size() == 0) { _MSG("No channels found - Remember, Kismet recently changed the format of " "channels, and to make it easier to find old configs, channels are now " "defined by the channellist=... config file line. Please check the " "Kismet devel blog for details and update your config file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } for (unsigned int x = 0; x < chan_vec.size(); x++) { if (AddChannelList(chan_vec[x]) == 0) { _MSG("Failed to add channel list '" + chan_vec[x] + "', check your " "syntax and remember Kismet recently changed how it handles " "channels!", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } // Process sources for (unsigned int x = 0; x < src_input_vec.size(); x++) { uint16_t id = 0; if (AddPacketSource(src_input_vec[x], NULL, &id) < 0) { _MSG("Failed to add source '" + src_input_vec[x] + "', check your " "syntax and remember Kismet recently changed how it handles " "source definitions!", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } // Figure out our split channel assignments by mapping assigned counts, // then checking to see if we're sharing on any sources which have // differing dwell/hop rates and warn, then assign offsets map chanid_count_map; for (map::iterator x = packetsource_map.begin(); x != packetsource_map.end(); ++x) { if (x->second->channel_hop == 0 || x->second->channel_split == 0) continue; if (chanid_count_map.find(x->second->channel_list) == chanid_count_map.end()) { chanid_count_map[x->second->channel_list] = 1; } else { chanid_count_map[x->second->channel_list]++; } } // Second check for mismatched dwell, nasty multiple-search of the map // but we don't care since it's a short map and we only do this during // startup for (map::iterator x = chanid_count_map.begin(); x != chanid_count_map.end(); ++x) { int chrate = -1, chdwell = -1; for (map::iterator y = packetsource_map.begin(); y != packetsource_map.end(); ++y) { if (y->second->channel_list != x->first || y->second->channel_hop == 0 || y->second->channel_split == 0) continue; if (chrate < 0) chrate = y->second->channel_rate; if (chdwell < 0) chdwell = y->second->channel_dwell; string warntype; if (chrate != y->second->channel_rate) warntype = "hop rate"; if (chdwell != y->second->channel_dwell) warntype = "dwell time"; if (warntype != "") { _MSG("Mismatched " + warntype + " for source '" + y->second->strong_source->FetchInterface() + "' splitting " "channel list " + channellist_map[x->first]->name + ". " "Mismatched " + warntype + " values will cause split hopping " "to drift over time.", MSGFLAG_ERROR); } } } // Third pass to actually assign offsets to our metasources for (map::iterator x = chanid_count_map.begin(); x != chanid_count_map.end(); ++x) { // We don't worry about channel splitting if we have 1 ("or fewer") sources // and we don't worry about anything which doesn't have an assigned // channel list (list id 0) if (x->second < 2 || x->first == 0) continue; int offset = 1 + (channellist_map[x->first]->channel_vec.size() / x->second); int offnum = 0; for (map::iterator y = packetsource_map.begin(); y != packetsource_map.end(); ++y) { if (y->second->channel_list != x->first || y->second->channel_hop == 0 || y->second->channel_split == 0) continue; y->second->channel_position = offnum * offset; offnum++; // Push it to the IPC SendIPCChanset(y->second); } } // Clear the named vec so we don't use it to compare enable sources again named_vec.clear(); return 1; } int Packetsourcetracker::IpcAddChannelList(ipc_source_add_chanlist *in_ipc) { pst_channellist *chlist; // Replace channel lists if we get the same one if (channellist_map.find(in_ipc->chanset_id) != channellist_map.end()) { chlist = channellist_map[in_ipc->chanset_id]; chlist->channel_vec.clear(); } else { chlist = new pst_channellist; channellist_map[in_ipc->chanset_id] = chlist; } for (unsigned int x = 0; x < kismin(IPC_SOURCE_MAX_CHANS, in_ipc->num_channels); x++) { pst_channel ch; // Derive from high bit in channel ch.range = in_ipc->chandata[x].u.range_t.start >> 15; if (ch.range == 0) { ch.u.chan_t.channel = in_ipc->chandata[x].u.chan_t.channel; ch.u.chan_t.dwell = in_ipc->chandata[x].u.chan_t.dwell; } else { // Extract the start (mask the high bit used to indicate range) ch.u.range_t.start = in_ipc->chandata[x].u.range_t.start & ~(1 << 15); ch.u.range_t.end = in_ipc->chandata[x].u.range_t.end; ch.u.range_t.width = in_ipc->chandata[x].u.range_t.width; ch.u.range_t.iter = in_ipc->chandata[x].u.range_t.iter; } /* ch.channel = in_ipc->chan_list[x]; ch.dwell = in_ipc->chan_dwell_list[x]; */ chlist->channel_vec.push_back(ch); } return 1; } int Packetsourcetracker::IpcAddPacketsource(ipc_source_add *in_ipc) { string interface; vector options; string in_source = string(in_ipc->sourceline); size_t pos = in_source.find(":"); pst_packetsource *pstsource = NULL; int found = 0; pstsource = new pst_packetsource; pstsource->local_only = 0; pstsource->sourceline = string(in_ipc->sourceline); pstsource->strong_source = NULL; pstsource->proto_source = NULL; // Import from the IPC packet pstsource->channel = in_ipc->channel; pstsource->channel_list = in_ipc->channel_id; pstsource->channel_ptr = NULL; pstsource->channel_hop = in_ipc->channel_hop; pstsource->channel_dwell = in_ipc->channel_dwell; pstsource->channel_rate = in_ipc->channel_rate; pstsource->channel_position = in_ipc->channel_position; pstsource->error = 0; pstsource->reopen = 1; pstsource->tm_hop_start.tv_sec = 0; pstsource->tm_hop_start.tv_usec = 0; pstsource->tm_hop_time.tv_sec = 0; pstsource->tm_hop_time.tv_usec = 0; pstsource->rate_timer = 0; pstsource->dwell_timer = 0; pstsource->consec_channel_err = 0; pstsource->zeropoll = 0; // We assume all our incoming data is valid but we'll check everything again // just to be sure if (pos == string::npos) { interface = in_source; if (interface.find(",") != string::npos) { _MSG("Found a ',' in the interface. This probably means the ncsource " "line is malformed - expected ncsource=interface:options", MSGFLAG_ERROR); } } else { interface = in_source.substr(0, pos); if (StringToOpts(in_source.substr(pos + 1, in_source.size() - pos - 1), ",", &options) < 0) { _MSG("Invalid options list for source '" + interface + "', expected " "ncsource=interface[:option=value,]", MSGFLAG_ERROR); pstsource->error = 1; SendIPCReport(pstsource); delete pstsource; return -1; } } pstsource->interface = interface; string type = string(in_ipc->type); for (unsigned int x = 0; x < protosource_vec.size(); x++) { if (protosource_vec[x]->type == StrLower(type)) { found = 1; pstsource->proto_source = protosource_vec[x]; break; } } // These shouldn't happen but send it back as an error if it does if (found == 0) { _MSG("Invalid type '" + type + "'; Unknown, or support was not " "compiled into this build of Kismet, check the output of the 'configure' " "script if you compiled Kismet yourself.", MSGFLAG_ERROR); pstsource->error = 1; SendIPCReport(pstsource); delete pstsource; return -1; } // check the channel if (channellist_map.find(pstsource->channel_list) == channellist_map.end()) { _MSG("Packet source IPC got a source with an invalid channel list id, " "this should never happen, check that all code sending sources sends " "channel list updates first", MSGFLAG_ERROR); pstsource->error = 1; SendIPCReport(pstsource); delete pstsource; return -1; } pstsource->channel_ptr = channellist_map[pstsource->channel_list]; // Build a strong source now that we know how, this parses any source-local // options in the source string that we can't pre-process. This shouldn't // error since we've already passed this stage before pstsource->strong_source = pstsource->proto_source->weak_source->CreateSource(globalreg, interface, &options); // All the hop/dwell/etc code is done on the server before it comes to us over IPC // Add the created strong source to our list pstsource->source_id = in_ipc->source_id; packetsource_map[pstsource->source_id] = pstsource; packetsource_vec.push_back(pstsource); return 1; } int Packetsourcetracker::IpcChannelSet(ipc_source_chanset *in_ipc) { pst_packetsource *pstsource = NULL; if (packetsource_map.find(in_ipc->source_id) == packetsource_map.end()) { _MSG("Packet source IPC unable to find requested source id for " "channel set, something is wrong", MSGFLAG_ERROR); return -1; } pstsource = packetsource_map[in_ipc->source_id]; if (in_ipc->chanset_id != 0 && channellist_map.find(in_ipc->chanset_id) == channellist_map.end()) { _MSG("Packet source IPC unable to find requested channel id for " "channel set, something is wrong", MSGFLAG_ERROR); } if (in_ipc->channel_hop == 0 && in_ipc->channel_dwell == 0) { // Actually set the channel if we're locking pstsource->channel = in_ipc->channel; if (pstsource->strong_source->SetChannel(pstsource->channel) < 0) _MSG("Packet source failed to set channel on source '" + pstsource->strong_source->FetchName() + "'", MSGFLAG_ERROR); } // Update other info if (channellist_map.find(in_ipc->chanset_id) != channellist_map.end()) { pstsource->channel_position = in_ipc->channel_pos; pstsource->range_position = 0; pstsource->channel_list = in_ipc->chanset_id; pstsource->channel_ptr = channellist_map[in_ipc->chanset_id]; } else { _MSG("Packet source failed to set channel set id on source '" + pstsource->strong_source->FetchName() + "' couldn't match chanset ID", MSGFLAG_ERROR); } pstsource->channel_hop = in_ipc->channel_hop; pstsource->channel_dwell = in_ipc->channel_dwell; pstsource->channel_rate = in_ipc->channel_rate; pstsource->channel_split = in_ipc->channel_split; return 1; } int Packetsourcetracker::IpcSourceReport(ipc_source_report *in_ipc) { pst_packetsource *pstsource = NULL; if (packetsource_map.find(in_ipc->source_id) == packetsource_map.end()) { _MSG("Packet source tracker unable to find source id for " "report, something is wrong", MSGFLAG_ERROR); return -1; } pstsource = packetsource_map[in_ipc->source_id]; // Copy the hop timestamp pstsource->tm_hop_time.tv_sec = in_ipc->hop_tm_sec; pstsource->tm_hop_time.tv_usec = in_ipc->hop_tm_usec; // Copy the last channel we were on pstsource->channel = in_ipc->last_channel; if ((in_ipc->flags) & IPC_SRCREP_FLAG_ERROR) { if (pstsource->reopen && pstsource->error == 0) { _MSG("Packet source '" + pstsource->strong_source->FetchName() + "' " "encountered an error, Kismet will attempt to reopen it in " "10 seconds", MSGFLAG_ERROR); } pstsource->error = 1; } return 1; } int Packetsourcetracker::IpcSourceRun(ipc_source_run *in_ipc) { if (in_ipc->start) return StartSource(in_ipc->source_id); else return StopSource(in_ipc->source_id); return 1; } int Packetsourcetracker::IpcSourceRemove(ipc_source_remove *in_ipc) { pst_packetsource *pstsource = NULL; if (running_as_ipc == 0) return 0; if (packetsource_map.find(in_ipc->source_id) == packetsource_map.end()) { _MSG("Packet source tracker unable to find source id for " "remove, something is wrong", MSGFLAG_ERROR); return -1; } pstsource = packetsource_map[in_ipc->source_id]; return RemovePacketSource(pstsource); } int Packetsourcetracker::IpcPacket(ipc_source_packet *in_ipc) { pst_packetsource *pstsource = NULL; kis_packet *newpack = NULL; // Stop processing during shutdown if (globalreg->spindown) return 0; if (running_as_ipc == 1) return 0; if (packetsource_map.find(in_ipc->source_id) == packetsource_map.end()) { _MSG("Packet source tracker unable to find source id for " "packet, something is wrong", MSGFLAG_ERROR); return -1; } pstsource = packetsource_map[in_ipc->source_id]; if (pstsource->strong_source != NULL) pstsource->strong_source->AddPacketCount(); newpack = globalreg->packetchain->GeneratePacket(); newpack->ts.tv_sec = in_ipc->tv_sec; newpack->ts.tv_usec = in_ipc->tv_usec; kis_datachunk *linkchunk = new kis_datachunk; linkchunk->dlt = in_ipc->dlt; linkchunk->source_id = in_ipc->source_id; linkchunk->data = new uint8_t[in_ipc->pkt_len]; linkchunk->length = in_ipc->pkt_len; memcpy(linkchunk->data, in_ipc->data, in_ipc->pkt_len); newpack->insert(_PCM(PACK_COMP_LINKFRAME), linkchunk); kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = pstsource->strong_source; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); globalreg->packetchain->ProcessPacket(newpack); return 1; } int Packetsourcetracker::IpcChannelReport(ipc_source_chanreport *in_ipc) { for (unsigned int x = 0; x < in_ipc->num_channels; x++) { channel_tick_map[in_ipc->channels[x]] = in_ipc->channels_time[x]; } return 1; } int Packetsourcetracker::StartSource(uint16_t in_source_id) { #ifndef SYS_CYGWIN uid_t euid = geteuid(); #else uid_t euid = 0; #endif pst_packetsource *pstsource = NULL; int failure = 0; // Start all sources. Incrementally count failure conditions and let the caller // decide how to deal with them if (in_source_id == 0) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (StartSource(packetsource_vec[x]->source_id) < 0) failure--; } return failure; } // printf("debug - %d - startsource %d - ipc %d uid %d\n", getpid(), in_source_id, running_as_ipc, euid); if (packetsource_map.find(in_source_id) != packetsource_map.end()) { pstsource = packetsource_map[in_source_id]; } else { _MSG("Packetsourcetracker::StartSource called with unknown packet source " "id, something is wrong.", MSGFLAG_ERROR); // printf("debug - %d - unknown packet source\n", getpid()); return -1; } // Nothing to do if we don't have a complete source (like a really broken // startup source) if (pstsource->strong_source == NULL) { // printf("debug - %d - strong source null\n", getpid()); return 0; } if (pstsource->proto_source != NULL && euid != 0 && pstsource->proto_source->require_root && running_as_ipc) { _MSG("IPC child Source '" + pstsource->strong_source->FetchInterface() + "' requires root permissions to open, but we're not running " "as root. Something is wrong.", MSGFLAG_ERROR); pstsource->warning = "This source requires root privileges, but the root " "control process isn't running as root. Something is wrong with the " "install."; // printf("debug - %d - not running as root in ipc\n", getpid()); return -1; } else if (pstsource->proto_source != NULL && euid != 0 && pstsource->proto_source->require_root) { if (rootipc == NULL || ((RootIPCRemote *) rootipc)->FetchRootIPCSynced() <= 0) { _MSG("Packet source '" + pstsource->strong_source->FetchInterface() + "' " "requires root to start, but the root control process is not " "running and sycned.", MSGFLAG_ERROR); pstsource->error = 1; pstsource->warning = "Packet source requires root privileges, but the " "root control process isn't running. Check the server error logs."; // printf("debug - %d - requires root ad we do't have an ipc\n", getpid()); return -1; } _MSG("Deferring opening of packet source '" + pstsource->strong_source->FetchInterface() + "' to IPC child", MSGFLAG_INFO); SendIPCStart(pstsource); // Assume we're not in error state, we'll get an IPC back if we are pstsource->error = 0; return 0; } // printf("debug - %d - starting to open source\n", getpid()); pstsource->error = 0; // Enable monitor and open it, because we're either the IPC and root, // or the parent and root, or we're going to fail pstsource->strong_source->SetSourceID(pstsource->source_id); // Don't decode the DLT if we're the IPC target if (running_as_ipc) pstsource->strong_source->SetDLTMangle(0); if (pstsource->strong_source->EnableMonitor() < 0) { pstsource->error = 1; SendIPCReport(pstsource); return -1; } if (pstsource->strong_source->OpenSource() < 0) { pstsource->error = 1; SendIPCReport(pstsource); return -1; } if (pstsource->channel > 0) { pstsource->strong_source->SetChannel(pstsource->channel); SendIPCChanreport(); } else { int tint = pstsource->strong_source->FetchHardwareChannel(); if (tint > 0) { pstsource->channel = (uint16_t) tint; SendIPCChanreport(); } } _MSG("Started source '" + pstsource->strong_source->FetchName() + "'", MSGFLAG_INFO); SendIPCReport(pstsource); return 0; } int Packetsourcetracker::StopSource(uint16_t in_source_id) { #ifndef SYS_CYGWIN uid_t euid = geteuid(); #else uid_t euid = 0; #endif pst_packetsource *pstsource = NULL; int failure = 0; // Start all sources. Incrementally count failure conditions and let the caller // decide how to deal with them if (in_source_id == 0) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (StopSource(packetsource_vec[x]->source_id) < 0) failure--; } return failure; } if (packetsource_map.find(in_source_id) != packetsource_map.end()) { pstsource = packetsource_map[in_source_id]; } else { _MSG("Packetsourcetracker::StopSource called with unknown packet source " "id, something is wrong.", MSGFLAG_ERROR); return -1; } if (pstsource->strong_source == NULL) return 0; if (pstsource->proto_source != NULL && euid != 0 && pstsource->proto_source->require_root && running_as_ipc) { _MSG("IPC child Source '" + pstsource->strong_source->FetchInterface() + "' requires root permissions to shut down, but we're not running " "as root. Something is wrong.", MSGFLAG_ERROR); return -1; } else if (pstsource->proto_source != NULL && euid != 0 && pstsource->proto_source->require_root) { _MSG("Deferring shutdown of packet source '" + pstsource->strong_source->FetchInterface() + "' to IPC child", MSGFLAG_INFO); SendIPCStop(pstsource); return 0; } if (pstsource->strong_source->CloseSource() < 0) { SendIPCReport(pstsource); return -1; } if (pstsource->strong_source->DisableMonitor() < 0) { SendIPCReport(pstsource); return -1; } _MSG("Stopped source '" + pstsource->strong_source->FetchName() + "'", MSGFLAG_INFO); SendIPCReport(pstsource); return 0; } void Packetsourcetracker::SendIPCSourceAdd(pst_packetsource *in_source) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCSourceAdd(packetsource_vec[x]); } return; } if (in_source->local_only == 1) return; ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_add)); ipc_source_add *add = (ipc_source_add *) ipc->data; ipc->data_len = sizeof(ipc_source_add); ipc->ipc_ack = 0; ipc->ipc_cmdnum = source_ipc_id; add->source_id = in_source->source_id; snprintf(add->type, 64, "%s", in_source->strong_source->FetchType().c_str()); snprintf(add->sourceline, 1024, "%s", in_source->sourceline.c_str()); add->channel_id = in_source->channel_list; add->channel = in_source->channel; add->channel_hop = in_source->channel_hop; add->channel_dwell = in_source->channel_dwell; add->channel_rate = in_source->channel_rate; add->channel_position = in_source->channel_position; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCChannellist(pst_channellist *in_list) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_list == NULL) { for (map::iterator x = channellist_map.begin(); x != channellist_map.end(); ++x) { SendIPCChannellist(x->second); } return; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_add_chanlist)); ipc_source_add_chanlist *addch = (ipc_source_add_chanlist *) ipc->data; ipc->data_len = sizeof(ipc_source_add_chanlist); ipc->ipc_ack = 0; ipc->ipc_cmdnum = channellist_ipc_id; addch->chanset_id = in_list->channel_id; addch->num_channels = in_list->channel_vec.size(); for (unsigned int x = 0; x < kismin(IPC_SOURCE_MAX_CHANS, in_list->channel_vec.size()); x++) { if (in_list->channel_vec[x].range == 0) { addch->chandata[x].u.chan_t.channel = in_list->channel_vec[x].u.chan_t.channel; addch->chandata[x].u.chan_t.dwell = in_list->channel_vec[x].u.chan_t.dwell; } else { addch->chandata[x].u.range_t.start = in_list->channel_vec[x].u.range_t.start; // Flag it as a range addch->chandata[x].u.range_t.start |= (1 << 15); addch->chandata[x].u.range_t.end = in_list->channel_vec[x].u.range_t.end; addch->chandata[x].u.range_t.width = in_list->channel_vec[x].u.range_t.width; addch->chandata[x].u.range_t.iter = in_list->channel_vec[x].u.range_t.iter; } /* addch->chan_list[x] = in_list->channel_vec[x].channel; addch->chan_dwell_list[x] = in_list->channel_vec[x].dwell; */ } rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCReport(pst_packetsource *in_source) { if (running_as_ipc == 0) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCReport(packetsource_vec[x]); } return; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_report)); ipc_source_report *report = (ipc_source_report *) ipc->data; ipc->data_len = sizeof(ipc_source_report); ipc->ipc_ack = 0; ipc->ipc_cmdnum = report_ipc_id; report->source_id = in_source->source_id; report->chanset_id = in_source->channel_list; // TODO figure out capabilities report->capabilities = 0; report->flags = 0; if (in_source->strong_source != NULL) { if (in_source->strong_source->FetchDescriptor() >= 0) report->flags |= IPC_SRCREP_FLAG_RUNNING; } if (in_source->error) report->flags |= IPC_SRCREP_FLAG_ERROR; report->hop_tm_sec = (uint32_t) in_source->tm_hop_time.tv_sec; report->hop_tm_usec = (uint32_t) in_source->tm_hop_time.tv_usec; report->last_channel = in_source->channel; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCStart(pst_packetsource *in_source) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCStart(packetsource_vec[x]); } return; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_run)); ipc_source_run *run = (ipc_source_run *) ipc->data; ipc->data_len = sizeof(ipc_source_run); ipc->ipc_ack = 0; ipc->ipc_cmdnum = run_ipc_id; run->source_id = in_source->source_id; run->start = 1; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCStop(pst_packetsource *in_source) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCStop(packetsource_vec[x]); } return; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_run)); ipc_source_run *run = (ipc_source_run *) ipc->data; ipc->data_len = sizeof(ipc_source_run); ipc->ipc_ack = 0; ipc->ipc_cmdnum = stop_ipc_id; run->source_id = in_source->source_id; run->start = 0; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCChanset(pst_packetsource *in_source) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCChanset(packetsource_vec[x]); } return; } if (in_source->proto_source == NULL) return; if (in_source->proto_source->require_root == 0) return; ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_chanset)); ipc_source_chanset *chanset = (ipc_source_chanset *) ipc->data; ipc->data_len = sizeof(ipc_source_chanset); ipc->ipc_ack = 0; ipc->ipc_cmdnum = channel_ipc_id; chanset->source_id = in_source->source_id; chanset->chanset_id = in_source->channel_list; chanset->channel = in_source->channel; chanset->channel_hop = in_source->channel_hop; chanset->channel_dwell = in_source->channel_dwell; chanset->channel_rate = in_source->channel_rate; chanset->channel_split = in_source->channel_split; chanset->channel_pos = in_source->channel_position; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCRemove(pst_packetsource *in_source) { if (running_as_ipc == 1) return; if (rootipc == NULL) return; if (in_source == NULL) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { SendIPCRemove(packetsource_vec[x]); } return; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_remove)); ipc_source_remove *remove = (ipc_source_remove *) ipc->data; ipc->data_len = sizeof(ipc_source_remove); ipc->ipc_ack = 0; ipc->ipc_cmdnum = remove_ipc_id; remove->source_id = in_source->source_id; rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCPacket(kis_packet *in_pack, kis_datachunk *in_linkchunk) { if (running_as_ipc == 0) return; if (rootipc == NULL) return; ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_packet) + in_linkchunk->length); ipc_source_packet *pack = (ipc_source_packet *) ipc->data; ipc->data_len = sizeof(ipc_source_packet) + in_linkchunk->length; ipc->ipc_ack = 0; ipc->ipc_cmdnum = packet_ipc_id; pack->source_id = in_linkchunk->source_id; pack->tv_sec = in_pack->ts.tv_sec; pack->tv_usec = in_pack->ts.tv_usec; pack->dlt = in_linkchunk->dlt; pack->pkt_len = in_linkchunk->length; memcpy(pack->data, in_linkchunk->data, in_linkchunk->length); rootipc->SendIPC(ipc); } void Packetsourcetracker::SendIPCChanreport() { if (running_as_ipc == 0) return; if (rootipc == NULL) return; ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_source_chanreport)); ipc_source_chanreport *report = (ipc_source_chanreport *) ipc->data; ipc->data_len = sizeof(ipc_source_chanreport); ipc->ipc_ack = 0; ipc->ipc_cmdnum = chanreport_ipc_id; report->num_channels = kismin(channel_tick_map.size(), IPC_SOURCE_MAX_CHANS); unsigned int p = 0; for (map::iterator x = channel_tick_map.begin(); x != channel_tick_map.end() && p < IPC_SOURCE_MAX_CHANS; ++x) { report->channels[p] = x->first; report->channels_time[p] = x->second; p++; } rootipc->SendIPC(ipc); } int Packetsourcetracker::RegisterSourceActCallback(SourceActCallback in_cb, void *in_aux) { // Make a cb rec sourceactcb_rec *cbr = new sourceactcb_rec; cbr->cb = in_cb; cbr->auxdata = in_aux; cb_vec.push_back(cbr); return 1; } int Packetsourcetracker::RemoveSourceActCallback(SourceActCallback in_cb) { for (unsigned int x = 0; x < cb_vec.size(); x++) { if (cb_vec[x]->cb != in_cb) continue; delete cb_vec[x]; cb_vec.erase(cb_vec.begin() + x); return 1; } return 0; } int Packetsourcetracker::SetSourceHopping(uuid in_uuid, int in_hopping, uint16_t in_channel) { pst_packetsource *pstsource = NULL; for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source == NULL) continue; if (packetsource_vec[x]->strong_source->FetchUUID() == in_uuid) { pstsource = packetsource_vec[x]; break; } } if (pstsource == NULL) { _MSG("No packet source with UUID " + in_uuid.UUID2String() + " in change channel/hopping request", MSGFLAG_ERROR); return -1; } // Set the local info pstsource->channel_hop = in_hopping; pstsource->channel = in_channel; // Send it over IPC - we don't care if it's controlled locally SendIPCChanset(pstsource); // Send a notify to all the registered callbacks int opt; if (in_hopping) { opt = SOURCEACT_HOPENABLE; } else { opt = SOURCEACT_HOPDISABLE; // Set it locally if we need to if ((rootipc == NULL || (pstsource->proto_source != NULL && pstsource->proto_source->require_root == 0)) && in_hopping == 0) { if (pstsource->strong_source->SetChannel(pstsource->channel) < 0) _MSG("Packet source failed to set channel on source '" + pstsource->strong_source->FetchName() + "'", MSGFLAG_ERROR); } } for (unsigned int x = 0; x < cb_vec.size(); x++) { (*(cb_vec[x]->cb))(globalreg, pstsource, opt, 0, cb_vec[x]->auxdata); } return 1; } int Packetsourcetracker::SetSourceNewChannellist(uuid in_uuid, string in_channellist) { pst_packetsource *pstsource = NULL; for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source == NULL) continue; if (packetsource_vec[x]->strong_source->FetchUUID() == in_uuid) { pstsource = packetsource_vec[x]; break; } } if (pstsource == NULL) { _MSG("No packet source with UUID " + in_uuid.UUID2String() + " to change channel list", MSGFLAG_ERROR); return -1; } // Parse the new channel list uint16_t new_id = AddChannelList(in_channellist); if (new_id == 0) { _MSG("Failed to change source '" + pstsource->strong_source->FetchInterface() + "' UUID " + in_uuid.UUID2String().c_str() + " channel list because " "the provided channel list definition is not valid", MSGFLAG_ERROR); return -1; } // Set the source up pstsource->channel_list = new_id; pstsource->channel_position = 0; pstsource->channel_ptr = channellist_map[new_id]; // Send the channel update to switch us to the new list SendIPCChanset(pstsource); // Send a notify to all the registered callbacks for (unsigned int x = 0; x < cb_vec.size(); x++) { (*(cb_vec[x]->cb))(globalreg, pstsource, SOURCEACT_CHVECTOR, 0, cb_vec[x]->auxdata); } return 1; } int Packetsourcetracker::SetSourceHopDwell(uuid in_uuid, int in_rate, int in_dwell) { pst_packetsource *pstsource = NULL; for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source == NULL) continue; if (packetsource_vec[x]->strong_source->FetchUUID() == in_uuid) { pstsource = packetsource_vec[x]; break; } } if (pstsource == NULL) { _MSG("No packet source with UUID " + in_uuid.UUID2String() + " in change hop/dwell request", MSGFLAG_ERROR); return -1; } // Set the local info pstsource->channel_rate = in_rate; pstsource->channel_dwell = in_dwell; // Send it over IPC - we don't care if it's controlled locally SendIPCChanset(pstsource); // Send a notify to all the registered callbacks for (unsigned int x = 0; x < cb_vec.size(); x++) { (*(cb_vec[x]->cb))(globalreg, pstsource, SOURCEACT_CHHOPDWELL, 0, cb_vec[x]->auxdata); } return 1; } int Packetsourcetracker::AddLivePacketSource(string in_source, KisPacketSource *in_strong) { uint16_t new_id = 0; int ret; if ((ret = AddPacketSource(in_source, in_strong, &new_id)) < 0) { return -1; } if (ret == 0) return 1; StartSource(new_id); return 1; } pst_packetsource *Packetsourcetracker::FindLivePacketSource(KisPacketSource *in_strong) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source == in_strong) return packetsource_vec[x]; } return NULL; } pst_packetsource *Packetsourcetracker::FindLivePacketSourceUUID(uuid in_uuid) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source == NULL) continue; if (packetsource_vec[x]->strong_source->FetchUUID() == in_uuid) return packetsource_vec[x]; } return NULL; } pst_packetsource *Packetsourcetracker::FindLivePacketSourceName(string name) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->strong_source && packetsource_vec[x]->strong_source->FetchName() == name) return packetsource_vec[x]; } return NULL; } KisPacketSource *Packetsourcetracker::FindKisPacketSourceUUID(uuid in_uuid) { pst_packetsource *pst = FindLivePacketSourceUUID(in_uuid); if (pst != NULL) return pst->strong_source; return NULL; } int Packetsourcetracker::RemoveLivePacketSource(KisPacketSource *in_strong) { pst_packetsource *pstsource = FindLivePacketSource(in_strong); if (pstsource != NULL) return RemovePacketSource(pstsource); return 0; } int Packetsourcetracker::RemovePacketSource(pst_packetsource *in_source) { if (in_source == NULL) return 0; packetsource_map.erase(packetsource_map.find(in_source->source_id)); for (unsigned int x = 0; x < packetsource_vec.size(); x++) { if (packetsource_vec[x]->source_id == in_source->source_id) { packetsource_vec.erase(packetsource_vec.begin() + x); break; } } if (in_source->error == 0) { in_source->strong_source->CloseSource(); } SendIPCRemove(in_source); // Send a notify to all the registered callbacks for (unsigned int x = 0; x < cb_vec.size(); x++) { (*(cb_vec[x]->cb))(globalreg, in_source, SOURCEACT_DELSOURCE, 0, cb_vec[x]->auxdata); } delete in_source; return 1; } pst_channellist *Packetsourcetracker::FetchSourceChannelList(pst_packetsource *in_src) { if (channellist_map.find(in_src->channel_list) == channellist_map.end()) return NULL; return channellist_map[in_src->channel_list]; } void Packetsourcetracker::ChannelTimer() { // Is another source sharing this channel at this time? map channel_touched; for (unsigned int x = 0; x < packetsource_vec.size(); x++) { pst_packetsource *pst = packetsource_vec[x]; if (pst->strong_source == NULL || pst->channel_ptr == NULL || (pst->channel_hop == 0 && pst->channel_dwell == 0) || pst->error == 1) { continue; } // Hop sources we have open. Non-hoppable sources won't be set to hop if (pst->strong_source->FetchDescriptor() >= 0) { struct timeval tv; int push_report = 0; int channel = FreqToChan(pst->channel); if (pst->channel_hop) { // Only increment it for one packet source, if we have multiple // that are on the same channel if (channel_touched.find(channel) == channel_touched.end()) { channel_touched[channel] = 1; map::iterator ctmi; if ((ctmi = channel_tick_map.find(channel)) == channel_tick_map.end()) { channel_tick_map[channel] = 1; } else { ctmi->second++; } } pst->rate_timer--; if (pst->rate_timer > 0) { // fprintf(stderr, "debug - source %s timer %d\n", pst->interface.c_str(), pst->rate_timer); continue; } if (pst->channel_position >= (int) pst->channel_ptr->channel_vec.size()) { pst->channel_position = 0; push_report = 1; } if (pst->channel_ptr->channel_vec[pst->channel_position].range) { pst->rate_timer = (SERVER_TIMESLICES_SEC - pst->channel_rate); } else { pst->rate_timer = pst->channel_ptr->channel_vec[pst->channel_position].u.chan_t.dwell * (float) ((float) SERVER_TIMESLICES_SEC / (float) pst->channel_rate); // fprintf(stderr, "debug - set timer to %d dwell %d + slices %d - rate %d\n", pst->rate_timer, pst->channel_ptr->channel_vec[pst->channel_position].u.chan_t.dwell, SERVER_TIMESLICES_SEC, pst->channel_rate); } } else if (pst->channel_dwell) { pst->dwell_timer--; if (channel_touched.find(channel) == channel_touched.end()) { channel_touched[channel] = 1; map::iterator ctmi; if ((ctmi = channel_tick_map.find(channel)) == channel_tick_map.end()) { channel_tick_map[channel] = 1; } else { ctmi->second++; } } if (pst->dwell_timer > 0) { continue; } if (pst->channel_position >= (int) pst->channel_ptr->channel_vec.size()) { pst->channel_position = 0; push_report = 1; } // Ranges all dwell for the default if (pst->channel_ptr->channel_vec[pst->channel_position].range) pst->dwell_timer = pst->channel_dwell * SERVER_TIMESLICES_SEC; else pst->dwell_timer = pst->channel_ptr->channel_vec[pst->channel_position].u.chan_t.dwell * (SERVER_TIMESLICES_SEC * pst->channel_dwell); } else { if (channel_touched.find(channel) == channel_touched.end()) { channel_touched[channel] = 1; map::iterator ctmi; if ((ctmi = channel_tick_map.find(channel)) == channel_tick_map.end()) { channel_tick_map[channel] = 1; } else { ctmi->second++; } } } // Set and advertise the channel if (push_report) { gettimeofday(&tv, NULL); SubtractTimeval(&tv, &(pst->tm_hop_start), &(pst->tm_hop_time)); pst->tm_hop_start.tv_sec = tv.tv_sec; pst->tm_hop_start.tv_usec = tv.tv_usec; SendIPCReport(pst); } // Total for the range position, filled in if needed int range_t = 0; // Set the local channel via chanset or range if (pst->channel_ptr->channel_vec[pst->channel_position].range == 0) { pst->channel = pst->channel_ptr->channel_vec[pst->channel_position].u.chan_t.channel; } else { // total = ((end - start) / iteration) + 1 // jump = width / iteration // slot = (pos * jump) % total // chan = start + (slot * iteration) range_t = ((pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.end - pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.start) / pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.iter) + 1; int j = pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.width / pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.iter; int s = (pst->range_position * j) % range_t; pst->channel = pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.start + (s * pst->channel_ptr->channel_vec[pst->channel_position].u.range_t.iter); } // fprintf(stderr, "debug - hop list interface %s new channel %d\n", pst->interface.c_str(), pst->channel); if (pst->strong_source->FetchError() == 0 && pst->strong_source->SetChannel(pst->channel) < 0) { pst->consec_channel_err++; if (pst->strong_source->FetchError()) { _MSG("Packet source '" + pst->strong_source->FetchName() + "' has encountered an unrecoverable error setting channel " "and will be shut down.", MSGFLAG_ERROR); pst->strong_source->CloseSource(); pst->error = 1; } if (pst->consec_channel_err > MAX_CONSEC_CHAN_ERR) { _MSG("Packet source '" + pst->strong_source->FetchName() + "' has had too many consecutive errors and will be shut down.", MSGFLAG_ERROR); pst->strong_source->CloseSource(); pst->error = 1; } if (pst->error && pst->reopen) { _MSG("Kismet will attempt to re-open packet source '" + pst->strong_source->FetchName() + "' in 10 seconds", MSGFLAG_ERROR); } } else { pst->consec_channel_err = 0; } // if we're in a channel, we advance, otherwise if we're in a range // we need to advance the range position and then advance the channel // if we've completed the range if (pst->channel_ptr->channel_vec[pst->channel_position].range == 0) { pst->channel_position++; } else { pst->range_position++; if (pst->range_position >= range_t) { pst->range_position = 0; pst->channel_position++; } } } } timer_counter++; if (timer_counter == SERVER_TIMESLICES_SEC + 1) { timer_counter = 0; SendIPCChanreport(); ClearChannelTickMap(); } } void Packetsourcetracker::OpenTimer() { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { pst_packetsource *pst = packetsource_vec[x]; if (pst->reopen && pst->error) { _MSG("Attempting to re-open errored packet source " + pst->strong_source->FetchName(), MSGFLAG_INFO); StartSource(pst->source_id); } } } void Packetsourcetracker::ChainHandler(kis_packet *in_pack) { kis_datachunk *linkchunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME)); if (linkchunk == NULL) return; if (running_as_ipc) { // Send it through the IPC system SendIPCPacket(in_pack, linkchunk); } else { // Send it through the packet source demangler kis_ref_capsource *csrc_ref = (kis_ref_capsource *) in_pack->fetch(_PCM(PACK_COMP_KISCAPSRC)); if (csrc_ref == NULL) { _MSG("We got a packet in the PST chainhandler with data but no capsource " "reference so we don't know how to handle it, we're going to have " "to throw it on the floor, something is wrong.", MSGFLAG_ERROR); return; } csrc_ref->ref_source->ManglePacket(in_pack, linkchunk); } } void Packetsourcetracker::BlitSources(int in_fd) { for (unsigned int x = 0; x < packetsource_vec.size(); x++) { kis_protocol_cache cache; if (in_fd == -1) { if (globalreg->kisnetserver->SendToAll(source_protoref, (void *) packetsource_vec[x]) < 0) break; } else { if (globalreg->kisnetserver->SendToClient(in_fd, source_protoref, (void *) packetsource_vec[x], &cache) < 0) break; } } } void Packetsourcetracker::BlitProtoSources(int in_fd) { } int Packetsourcetracker::cmd_ADDSOURCE(int in_clid, KisNetFramework *framework, char *errstr, string cmdline, vector *parsedcmdline) { if (parsedcmdline->size() < 1) { snprintf(errstr, 1024, "Illegal ADDSOURCE command, expected source line"); return -1; } uint16_t new_source_id; int ret = AddPacketSource((*parsedcmdline)[0].word, NULL, &new_source_id); if (ret <= 0) { snprintf(errstr, 1024, "ADDSOURCE command failed"); return -1; } _MSG("Added source '" + (*parsedcmdline)[0].word + "' from client ADDSOURCE", MSGFLAG_INFO); if (StartSource(new_source_id) < 0) { snprintf(errstr, 1024, "ADDSOURCE failed to activate new source"); return -1; } snprintf(errstr, 1024, "Created new source"); return 1; } int Packetsourcetracker::cmd_DELSOURCE(int in_clid, KisNetFramework *framework, char *errstr, string cmdline, vector *parsedcmdline) { if (parsedcmdline->size() < 1) { snprintf(errstr, 1024, "Illegal DELSOURCE command, expected UUID"); return -1; } uuid inuuid = uuid((*parsedcmdline)[0].word); if (inuuid.error) { snprintf(errstr, 1024, "Invalid UUID in DELSOURCE command"); return -1; } pst_packetsource *pstsource = FindLivePacketSourceUUID(inuuid); if (pstsource == NULL) { snprintf(errstr, 1024, "Invalid UUID in DELSOURCE command, couldn't find " "source with UUID %s", inuuid.UUID2String().c_str()); return -1; } _MSG("Removing source '" + (*parsedcmdline)[0].word + "' from client DELSOURCE", MSGFLAG_INFO); RemovePacketSource(pstsource); return 1; } // HOPSOURCE uuid [HOP|DWELL|LOCK] [RATE|CHANNEL] int Packetsourcetracker::cmd_HOPSOURCE(int in_clid, KisNetFramework *framework, char *errstr, string cmdline, vector *parsedcmdline) { if (parsedcmdline->size() < 2) { snprintf(errstr, 1024, "Illegal HOPSOURCE command, expected UUID TYPE VAL"); return -1; } uuid inuuid = uuid((*parsedcmdline)[0].word); if (inuuid.error) { snprintf(errstr, 1024, "Invalid UUID in HOPSOURCE command"); return -1; } pst_packetsource *pstsource = FindLivePacketSourceUUID(inuuid); if (pstsource == NULL) { snprintf(errstr, 1024, "Invalid UUID in HOPSOURCE command, couldn't find " "source with UUID %s", inuuid.UUID2String().c_str()); return -1; } string cmd = StrLower((*parsedcmdline)[1].word); unsigned int val = 0; if (parsedcmdline->size() > 2) { if (sscanf((*parsedcmdline)[2].word.c_str(), "%u", &val) != 1) { snprintf(errstr, 1024, "Invalid value, expected number"); return -1; } } if (cmd == "lock") { if (parsedcmdline->size() < 2) { snprintf(errstr, 1024, "Expected channel for HOPSOURCE LOCK"); return -1; } SetSourceHopping(inuuid, 0, val); } else if (cmd == "hop") { if (parsedcmdline->size() < 2) { SetSourceHopping(inuuid, 1, 0); } else { SetSourceHopDwell(inuuid, val, 0); SetSourceHopping(inuuid, 1, 0); } } else if (cmd == "dwell") { if (parsedcmdline->size() < 2) { SetSourceHopping(inuuid, 1, 0); } else { SetSourceHopDwell(inuuid, 0, val); SetSourceHopping(inuuid, 1, 0); } } else { snprintf(errstr, 1024, "Expected LOCK, HOP or DWELL"); return -1; } return 1; } // CHANLIST uuid channels int Packetsourcetracker::cmd_CHANLIST(int in_clid, KisNetFramework *framework, char *errstr, string cmdline, vector *parsedcmdline) { if (parsedcmdline->size() < 2) { snprintf(errstr, 1024, "Illegal CHANLIST command, expected UUID " "chanlist"); return -1; } uuid inuuid = uuid((*parsedcmdline)[0].word); if (inuuid.error) { snprintf(errstr, 1024, "Invalid UUID in CHANLIST command"); return -1; } pst_packetsource *pstsource = FindLivePacketSourceUUID(inuuid); if (pstsource == NULL) { snprintf(errstr, 1024, "Invalid UUID in CHANLIST command, couldn't find " "source with UUID %s", inuuid.UUID2String().c_str()); return -1; } if (SetSourceNewChannellist(inuuid, pstsource->interface + string(":") + (*parsedcmdline)[1].word) < 0) { snprintf(errstr, 1024, "Failed to set channel list for source %s UUID %s", pstsource->interface.c_str(), inuuid.UUID2String().c_str()); return -1; } return 1; } int Packetsourcetracker::cmd_RESTARTSOURCE(int in_clid, KisNetFramework *framework, char *errstr, string cmdline, vector *parsedcmdline) { if (parsedcmdline->size() < 1) { snprintf(errstr, 1024, "Illegal DELSOURCE command, expected source line"); return -1; } uuid inuuid = uuid((*parsedcmdline)[1].word); if (inuuid.error) { snprintf(errstr, 1024, "Invalid UUID in DELSOURCE command"); return -1; } pst_packetsource *pstsource = FindLivePacketSourceUUID(inuuid); if (pstsource == NULL) { snprintf(errstr, 1024, "Invalid UUID in DELSOURCE command, couldn't find " "source with UUID %s", inuuid.UUID2String().c_str()); return -1; } _MSG("Restarting source '" + (*parsedcmdline)[1].word + "' from client " "RESTARTSOURCE", MSGFLAG_INFO); StopSource(pstsource->source_id); StartSource(pstsource->source_id); return 1; } kismet-2013-03-R1b/version.h0000664000175000017500000000166712124602454015323 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISVERSION_H__ #define __KISVERSION_H__ #define VERSION_MAJOR "2013" #define VERSION_MINOR "03" #define VERSION_TINY "R0" #define REVISION "$Rev$" #define REVDATE "$LastChangedDate$" #endif kismet-2013-03-R1b/CHANGELOG0000664000175000017500000005765312124602454014705 0ustar dragorndragornREMEMBER: I don't always update the changelog for newcore, check the SVN log for current progress Apr 20 2006 devel Fixed BSSID protocol in kismet_server Added various sources Added BSSID protocol decoder to client Apr 07 2006 devel Added server picker window Added "add source" window Mar 20 2006 devel Added keepalive to drone protocol Mar 12 2006 devel I know it's been a while, stuff going on in life, sorry. Added CARD protocol support to kp_frontend Changed behavior of kp_Scrollable_Table to add a row during a replace of a nonexistent row Feb 22 2006 devel Lots of un-changelog'd work in svn Increased max iwpriv ioctls per interface, will produce a different error on madwifi-ng using madwifi-old sources Finished cli matrix widget Added ModalAlert panel "File->Connect" actually connects to the Kismet server Feb 02 2006 devel More work on panels client Work on new tcp client code Fixed stupid error in server that didn't send capabilities Jan 16 2006 devel Finished client panel single input line widget Fixed menu not eating input when selecting nonexistent menus or items via keyboard Fixed consecutive disabled items in menus Fixed stupid error in window positioning Added button widget Added "Connect" demo window Jan 12 2006 devel Finished client panel menu widget code Finished client panel arbitrary text scroller widget code Added Madwifi-NG support (with dyanamic interface creation and destruction support) Removed prism2 header length validation, not needed and some drivers are broken Split widgets and windows into their own files Added client panel 2-field widget Added picking list type demo Added inline text style formatting class, added to freetext widget Jan 08 2006 devel Started newcore client development (Current client code is demo only and will not do anything useful) Changed menu drivers to go to menubar mode and allow picking the menu by underlined key Dec 29 2005 devel Added runstate loaders to kismet_server (do not use yet) Added runstate support to gpsxml Added runstate logging to netracker Added runstate loading to netracker Added runstate net totals logging/loading Runstate loading should be usable Dec 28 2005 devel Added runstate dumpfile framework for freezing the Kismet running state Tweaked runstate dumpfile parsing Added bcm43xx source Started adding dumpfile resume code Dec 21 2005 devel Fixed error in netframe caching Dec 19 2005 devel Added dynamic source creation/removal via ADDSOURCE and DELSOURCE commands Dec 18 2005 devel Fixed drone starting if drone server doesn't start Added --source-options command line switch Dec 16 2005 devel Fixed vector resize with uclibc++ Added uclibc++ autodetect in autoconf Added libm autodetect in autoconf Removed const qualifier in macaddr.h to allow compiling on uclibc c++ Dec 15 2005 devel Added remote drone name to messages passed from it Fixed drone stream syncing problem which caused sentinel errors Fixed compilation error when libpcap disabled Dec 14 2005 devel Fixed queuing of dumpfiles when dumping is disabled Dec 13 2005 devel Fixed loading of servername in server/drone Restored wrt54prism capture source for OpenWRT Fixed packet processing loop in packetsource_drone Dec 12 2005 devel Revamped AddSource callback API into a generic SourceAction API Wrote drone interface channel push code Added SourceAction hooks for setting hop, vectors Added drone server-side handling of channelset for hopping and vector Changed internal channel representation to unsigned int Added packet sending to drone client Added channelset packet generation to drone client Added proper bitmap handling of channelset frames in drone server Added channel sequence command (CHANSEQ) Fixed card commands (hop, etc) from segfaulting Fixed dumpfiles unregistering callbacks during destruction Fixed more blatant errors in uuid Fixed stupid errors in drone server handling Dec 11 2005 devel Added fix to ringbuf from Shane Schisler Added drone_source_packet generators to drone protocol to push a capture source upstream Added endian-flipping to bitmap fields in drone protocol Completed server side of drone interface push system Fixed UUID '<' operator Added remote source pushing via drone protocol, remote sources now show up Added purging of virtual sources when drone connection is broken Dec 10 2005 devel Added UUID to drone protocol Added LocalChannelHop() to packetsources to prevent conflicts with virtual drone interfaces Fixed compilation of new packetsource framework on BSD Fixed div-by-0 on channel assignment to virtual stuff like drones Fixed breaking drones by always splitting interfaces in packetsource.h Dec 05 2005 devel Began to add remote drone virtual sources Wrote some documentation on the new PacketSource api Dec 04 2005 devel Major code drop: - Moved root IPC for channel control out of packetsourcetracker - Rewrote how packetsourcetracker and packetsources work entirely - Added UUID tracking of each source * This code drop is KNOWN TO BREAK on *BSD and on compiling drones! I wanted to get it off my drive and versioned, more updates later tonight. Fixed drone to use new packetsource framework Set wext packet sources to pull UUID node from the interface MAC address Ported BSDRT source to new packetsource framework (untested) Nov 19 2005 devel Fixed quirks in drone protocol Implemented standalone kismet_drone binary Nov 18 2005 devel Did beginnings of drone packet source & client framework Activated packetsource_drone (does nothing yet) Initial drone support usable Nov 17 2005 devel Added 'sourceopts' config line to set per-source special options ('fuzzycrypt' moved to here, added 'weakvalidate' to loosen frame header validation restrictions) Nov 16 2005 devel Fixed up error exporting to do _LOCAL | _FOO Added command parsing to drone server Activated drone server in kismet_server.cc Fixed drone server stupidity Nov 15 2005 devel Standardized some error reporting in netframe Started drone protocol rewrite Nov 13 2005 devel Fixed netframe fatal oops to match other code Added float mantissa components to util Added globalreg component for non-char getopt Nov 11 2005 devel Fixed filtercore compiling on systems without libpcre Fixed dual-registration of STRING protocl Nov 10 2005 devel Added string extraction (currently always on) Added PCRE string filtering Fixed PCRE negation tests Fixed filter examples to show "00:11:.." quoted mac strings Added STRINGS (0|1) and ADDSTRINGSFILTER commands to toggle string fetching Added string logfile (type 'string') Added alert logtile (type 'alert') Nov 08 2005 devel Added libpcre checks to configure Fixed util.cc compiling process title stuff Added basic lexer to util.cc Re-implemented MAC address filtering Added stubs for pcre filters Added PCRE filter string parsing Fixed infinite loop in linewrapper Added filter_netclient and PCRE execution for SSID filters Nov 07 2005 devel Fixed encryption/decryption check for data dissectors Nov 03 2005 devel Added smarter error message if the card drops out of monitor Oct 30 2005 devel Docs, plugin tweaks Oct 29 2005 devel Updated info text on header mode iwprivs on linux Added set_prismhdr to default wext set Oct 28 2005 devel Updated README.newcore Oct 26 2005 devel Turned on assorted packet sources (ipw2915, admtek, prism54g) Oct 25 2005 devel Added checking for *.bz2 *.gz files in logfile enumeration Revamped attaching alerts to packets so that more than one alert can be tracked Cleaned up nettxt export Added backlogged alerts to nettxt output per network Added fetching alert backlog to alertracker Oct 23 2005 devel Added client CDP port/dev tracking Added client XML output Fixed rampant client allocation bug Fixed negative bsstimestamp in netxml Fixed negative datasize, aggpoints in netxml Added nettxt dumpfile Oct 22 2005 devel Added export filter initialization to dumpfile core Fixed pcap references from copying pcap dump to gpsxml Added netxml dumpfile Added hooks for fetching const maps of netracker internals Oct 21 2005 devel Smartened up linewrap Oct 20 2005 devel Implemented shutdown&cleanup of root capsources via IPC Fixed ieee80211 linktype Oct 19 2005 devel Cosmetic - added IPC child process name control Ported sound controller to IPC framework Moved speech/sound spawn to after privdrop Removed gpsdclient from globalreg Oct 18 2005 devel Fixed invalid handling of map when cleaning up kisclient protocols during a disconnect Ported speech handler to IPC framework Oct 17 2005 devel Fixed packetsourcetracker not being updated for meta msgclient Removed packetsource_bsd stub class Moved packetsource_bsd to packetsource_bsdrt Fixed up IPC framework to a working state Ported packetsource root controller to IPC framework Oct 16 2005 devel Added tracker meta to packsources for chain components to access Added "monitor_mode" ioctl set attempt to generic monitor Fixed gpscore/gpsdclient double pollable registration Fixed gpsdclient parsing more Added void* aux pointer to message clients for incoming IPC_remote generic and other message clients linked to replication of messages (netframe) Added IPC generic framework (incomplete) Took drone/client/etc out of Makefile for now Oct 13 2005 devel Converted BSD interface control framework from stable Removed radiotap availability check, since we force it on with local headers now anyhow Fixed local radiotap inclusion Fleshed out BSD capture sources Added CRYPTODROP alert for networks dropping advertised encryption Changed network/client crypto tracking to take the last advertised crypto set instead of the aggregate of all crypto ever seen Added per-sec throttling to kismet.conf defaults Oct 12 2005 devel Tweaked configure for BSD radiotap detection Removed some OS specific stuff from generic pcapsource Removed -O2 from default makefile cxxflags (oops) Oct 10 2005 devel Removed wext22 check from configure (unneeded) Cleaned up more of the configure file Set auto-fail for missing wext headers on linux Changed config warning for disabling wext Removed netlink socket checking from configure Oct 09 2005 devel Started adding failure conditions to autoconf and forcing explicit disabling of expected components (like ncurses) which is the "right" thing to do. Removed some linux-specific stuff from the radiotap header, renamed it to local_radiotap_header.h Oct 06 2005 devel Removed double-cache-lookup in NETWORK protocol handler Removed double-cache-lookup in CLIENT protocol handler Oct 04 2005 devel Moved versioning into header file for plugins to draw from Removed the timestamp file and zeroed out the timestamp element in the protocol. This should have been done a long time ago. Sep 29 2005 devel Various BSD related fixups, buffer size checks Added libdl check to autoconf (for BSD systems) Sep 26 2005 devel Moved dirty network and client tracking into vector, fixed constantly sending networks Sep 21 2005 devel Split GPS into gpscore and gpsdclient in anticipation of adding additional GPS capture methods Sep 20 2005 devel Implemented INFO protocol, added additional fields, deprecated 'signal' field Fixed maxsignal initialization in SNR fields Sep 19 2005 devel Fixed config file cmdline option Finished redoing CARD protocol Fixed stupid error in gpsxml logging Sep 18 2005 devel Moved CARD protocol into packetsourcetracker Fixed "client ring buffer full" message going into the client ring buffer Fixed loop in clinetframe kill procedure, fixed hammering "Socket closed" error messages Fixed gpsd reconnect if nothing to connect to Sep 17 2005 devel Added tracking of multiple SSIDs per network, and tracking all networks a client has probed for. No methods to export this information yet. Added removal abilities for client commands and network protocols in netframe Added auxptr to network protocols for enable functions to hook a class Added plugin listing protocol Added plugin shutdown Put plugintracker in globalreg Sep 15 2005 devel Added user plugin directory scanning and loading Implemented actually kickstarting the plugins Made better errors for dlopen() being stupid Fixed plugin symbol exporting Wrote demo NULL plugin (crappy example, better to come) Plugins should now be functional. YOU WILL NEED TO RERUN CONFIGURE for plugins to enable properly, you will also need to turn on 'allowplugins=true' in your config file. Sep 14 2005 devel Imported -stable autoconf with all its little fixes Added LIB_LOC to config.h Fixed config.h.bot glitch Changed privdrop behavior to keep running when there is a user/target mismatch provided neither is root, and kismet isn't started as root. (ie, Kismet configured to drop to 'bob', started as 'susan', now runs as 'susan' with an error warning) Added linewrap to fataloutput message client Added plugin core (funny how small a note that is) and started plugin loaders Sep 12 2005 devel Added per-network and per-client packet rate data Added packetrate fields to NETWORK and CLIENT protos Sep 11 2005 devel Turned on hostap (straight 'mode foo' control, no priv monitor) Started new filter core class Added filtering to netracker for filter_tracker Removed 'FILTER' packetchain stage since it's not going to be used that way Fixed AVS handling Fixed class overload of fcsbytes causing all sorts of issues Fixed some errors with compiling with suid disabled Added ADDTRACKERFILTER client command to nettracker Sep 10 2005 devel Turned on ipw2100 source again Turned on acx100 source (kluge to hopefully work with modern acx100 drivers) Turned on atmel-usb sourceA Turned on rt2400, rt2500, rt8180 Sep 09 2005 devel Started implementing 'auto' device support Skeleton of 'auto' capsource in place (for the one capsource newcore supports currently) Added Madwifi capsource back Sep 08 2005 devel Added BCASTDISCON and AIRJACKSSID alerts Sep 07 2005 devel Fixed client/server protocol caching Added probereq SSID tracking Added tracked network type updating Changed timestamp/timetracker set/tick to head of loop Added 'retry' flag to ieee80211 packet info Added fragments/retries tracking Added fragments and retries to CLIENT and NETWORK protocols Fixed CLIENT protocol enable Added CLIENT to nettracker tick Sep 06 2005 devel Added some support for flooding clients with more than the ringbuf can handle Sep 05 2005 devel Fixed DHCP handling Fixed UDP handling Fixed packetchain ordering Added IP tracking Fixed network/client packet attachments Sep 04 2005 devel Started adding data processing, IP guessing Added DHCPCONFLICT alert to catch multiple DHCP servers on one network. Maybe a little too layer-3ish Added CDP ids to NETWORK protocol Added client creation and association Sep 03 2005 devel Fixed CDP processing Sep 02 2005 devel Fixed alert on channel 0 networks getting a channel Fixed treating probe req, disassoc, auth, and death as frames that have a normal fixparm Fixed IAPP handling Added CDP support (untested) Sep 01 2005 devel Added timer kick to netracker to push network updates to kismet clients Fixed numerous uses of unitialzed memory Fixed gaping memory leakage due to destructor inheritance Aug 31 2005 devel Added WEP decryptor, MANGLE packet element, updated pcap and tun loggers to write the mangled frame Added Adler-32 checksum to util.[h|cc] Added bsstimestamp network field Fixed gpsd adding null data to each frame Fixed turbocell nid returning \001 buffered crap Fixed newcore server working with existing client Aug 29 2005 devel Added writeinterval support Aug 27 2005 devel Added auxptr to client command pointers Moved wepkey code into private functions in kisbuiltindis Aug 26 2005 devel Moved wepkey loading code and network protocols into packetdissectors.cc/kisbuiltindissector Aug 25 2005 devel Data dissector cleanup, merged packinfo crypset into data Aug 24 2005 devel Added constants for IAPP/other data sizes Added ARP ip dissector, generic IP dissector Added IAPP dissector (untested) Added DHCP dissector (untested) Added ISAKMP dissector (untested) Aug 23 2005 devel Added 16/32/64 bit ptr extractor Added EAP data detection (untested) Aug 22 2005 devel Fixed opening tcpserver before channel child Moved packet dissectors into helper class Moved packet registration and alert stuff into dissector helper class Added data dissection framework Added lucent signatures/detection/alert Aug 20 2005 devel Fixed alerts again (parsing enable lines) Restored '-s/--silent' cmd line option for server Implemented --help and cross-module --help output Aug 19 2005 devel Fixed some header wonkiness Started implementing alert framework (mostly there) Added alert rate parsing from config files Added --no-line-wrap for grep behavior Fixed alerts Activated channel change network alert Aug 18 2005 devel Restored WPA tag dissection from stable Fixed over-aggressive "new network detected" Added linewrap to stdout text and fixed linewrap code boundary checks, made linewrap word length relational Added extended supported rates support Aug 17 2005 devel Started implementing server protocol generic caching to eliminate the use of crummy vector converts of the entire struct Began enabling netracker NETWORK protocol Finished netracker NETWORK protocol rewrite Finished netracker CLIENT protocol rewrite Aug 14 2005 devel Added tun/tap virtual interface support for sharing packets Added patches/ dir and linux kernel patch for tuntap Fixed stupid timing inversion on channel hop Aug 13 2005 devel Resumed use of CHANGELOG file for newcore development as it is finally on its feet enough Added GPS-only packetchain data injection to gpsdclient Moved startup time and current timestamp to timetracker Changed global timestamp to usec precision Added GPSXML dumpfile module Change dumpfile superclass dumpfile name generation Added Flush() to dumpfile superclass and subs Added README.newcore Fixed gpsd parsing of \0 characters Fixed closing dumpfiles Echo client command errors to messagebus Added placeholder WEP field for clients Started phasing out broken protocol references to tracktypes networks, commented out network protocols for now --- -- ---- ----- Newcore changelog started kismet-2013-03-R1b/plugintracker.cc0000664000175000017500000003563312124602454016646 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "configfile.h" #include "getopt.h" #include "messagebus.h" #include "plugintracker.h" #include "kis_netframe.h" #include "version.h" // Plugin protocol stuff enum PLUGIN_fields { PLUGIN_fname, PLUGIN_name, PLUGIN_version, PLUGIN_description, PLUGIN_unloadable, PLUGIN_root, PLUGIN_maxfield }; const char *PLUGIN_fields_text[] = { "filename", "name", "version", "description", "unloadable", "root", NULL }; int Protocol_PLUGIN(PROTO_PARMS) { Plugintracker::plugin_meta *meta = (Plugintracker::plugin_meta *) data; for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= PLUGIN_maxfield) { out_string = "Unknown field requests"; return -1; } switch (fnum) { case PLUGIN_fname: out_string += "\001" + MungeToPrintable(meta->objectname) + "\001"; break; case PLUGIN_name: out_string += "\001" + MungeToPrintable(meta->usrdata.pl_name) + "\001"; break; case PLUGIN_version: out_string += "\001" + MungeToPrintable(meta->usrdata.pl_version) + "\001"; break; case PLUGIN_description: out_string += "\001" + MungeToPrintable(meta->usrdata.pl_description) + "\001"; break; case PLUGIN_unloadable: if (meta->usrdata.pl_unloadable) out_string += "1"; else out_string += "0"; break; case PLUGIN_root: if (meta->root) out_string += "1"; else out_string += "0"; break; } out_string += " "; } return 1; } void Protocol_PLUGIN_enable(PROTO_ENABLE_PARMS) { Plugintracker *ptrak = (Plugintracker *) data; ptrak->BlitPlugins(in_fd); return; } Plugintracker::Plugintracker() { fprintf(stderr, "FATAL OOPS: Plugintracker() called with no globalreg\n"); exit(1); } Plugintracker::Plugintracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Plugintracker called while config is NULL\n"); exit(1); } if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: Plugintracker called while netframe is NULL\n"); exit(1); } int option_idx = 0; int cmdline_disable = 0; int config_disable = 0; // Longopts static struct option plugin_long_options[] = { { "disable-plugins", no_argument, 0, 10 }, { 0, 0, 0, 0 } }; optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-", plugin_long_options, &option_idx); if (r < 0) break; switch (r) { case 10: cmdline_disable = 1; break; } } if (globalreg->kismet_config->FetchOpt("allowplugins") == "true") { config_disable = 0; } else { config_disable = 1; } plugins_protoref = globalreg->kisnetserver->RegisterProtocol("PLUGIN", 0, 0, PLUGIN_fields_text, &Protocol_PLUGIN, &Protocol_PLUGIN_enable, this); if (config_disable || cmdline_disable) { plugins_active = 0; _MSG("Plugin system disabled by Kismet configuration file or command line", MSGFLAG_INFO); return; } plugins_active = 1; } Plugintracker::~Plugintracker() { // Call the main shutdown, which should kill the vector allocations ShutdownPlugins(); globalreg->kisnetserver->RemoveProtocol(plugins_protoref); } void Plugintracker::Usage(char *name) { printf(" *** Plugin Options ***\n"); printf(" --disable-plugins Turn off the plugin system\n"); } int Plugintracker::ScanRootPlugins() { // Bail if plugins disabled if (plugins_active == 0) return 0; // Fetch the list of root plugins vector root_plugin_names = globalreg->kismet_config->FetchOptVec("rootplugin"); if (root_plugin_names.size() == 0) return 0; // Don't even bother doing anything special if we're not root, just // msg and drop out, they'll get loaded as userpriv and fail or succeed as // they will. if (getuid() != 0) { _MSG("Not running as root, skipping root plugin load process. Any plugins " "which require root privs will not load properly.", MSGFLAG_ERROR); return 0; } string plugin_path = string(LIB_LOC) + "/kismet/"; // Stat the directory holding the plugins struct stat filestat; if (stat(plugin_path.c_str(), &filestat) < 0) { _MSG("Failed to stat the primary plugin directory (" + plugin_path + "): " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Make sure its owned by root if (filestat.st_uid != 0 || filestat.st_gid != 0) { _MSG("The primary plugin directory (" + plugin_path + ") is not owned by " "root:root. For security, Kismet requires that the directory be owned " "by root if plugins are loaded before the privdrop. See the " "'Installation & Security' and 'Configuration' sections of the README " "file for more information about the security measures used by Kismet " "and the proper permissions for the plugin directory.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if ((filestat.st_mode & (S_IWGRP | S_IWOTH))) { _MSG("The primary plugin directory (" + plugin_path +") does not have secure " "file permissions. This could allow modification of plugins which load " "before the privdrop. See the 'Installation & Security' and " "'Configuration' sections of the README file for more information about " "the security measures used by Kismet and the proper permissions for " "the plugin directory.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Start checking the plugins for (unsigned int x = 0; x < root_plugin_names.size(); x++) { string rootplugname = plugin_path + root_plugin_names[x]; if (stat(rootplugname.c_str(), &filestat) < 0) { _MSG("Failed to stat specified root plugin '" + root_plugin_names[x] + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if ((filestat.st_mode & (S_IWGRP | S_IWOTH))) { _MSG("The plugin '" + root_plugin_names[x] + "' does not have secure " "file permissions. This could allow the modification of plugins " "which load before the privdrop. See the 'Installation & Security' " "and 'Configuration' sections of the README file for more " "information about the security measures used by Kismet and proper " "permissions for plugins.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Load the meta plugin into our vector plugin_meta *meta = new plugin_meta; meta->filename = rootplugname; meta->objectname = root_plugin_names[x]; meta->root = 1; plugin_vec.push_back(meta); } return 1; } int Plugintracker::ScanUserPlugins() { // Bail if plugins disabled if (plugins_active == 0) return 0; string plugin_path = string(LIB_LOC) + "/kismet/"; DIR *plugdir; if ((plugdir = opendir(plugin_path.c_str())) == NULL) { _MSG("Failed to open primary plugin directory (" + plugin_path + "): " + strerror(errno), MSGFLAG_ERROR); } else { if (ScanDirectory(plugdir, plugin_path) < 0) return -1; closedir(plugdir); } string config_path; if ((config_path = globalreg->kismet_config->FetchOpt("configdir")) == "") { _MSG("Failed to find a 'configdir' path in the Kismet config file, " "ignoring local plugins.", MSGFLAG_ERROR); return 0; } plugin_path = globalreg->kismet_config->ExpandLogPath(config_path + "/plugins/", "", "", 0, 1); if ((plugdir = opendir(plugin_path.c_str())) == NULL) { _MSG("Failed to open user plugin directory (" + plugin_path + "): " + strerror(errno), MSGFLAG_ERROR); } else { if (ScanDirectory(plugdir, plugin_path) < 0) return -1; closedir(plugdir); } return 1; } int Plugintracker::ScanDirectory(DIR *in_dir, string in_path) { struct dirent *plugfile; int loaded; while ((plugfile = readdir(in_dir)) != NULL) { if (plugfile->d_name[0] == '.') continue; string fname = plugfile->d_name; // Found a .so loaded = 0; if (fname.find(".so") == fname.length() - 3) { // Look for the plugin in the vector. This is slow to iterate every // time, but it's only happening once at boot so i don't care. for (unsigned int x = 0; x < plugin_vec.size(); x++) { if (plugin_vec[x]->filename == in_path + fname) { loaded = 1; break; } } if (loaded) continue; // Load the meta plugin into our vector plugin_meta *meta = new plugin_meta; meta->filename = in_path + fname; meta->objectname = fname; meta->root = 0; plugin_vec.push_back(meta); } } return 1; } // Catch plugin failures so we can alert the user string global_plugin_load; void PluginServerSignalHandler(int sig) { fprintf(stderr, "\n\n" "FATAL: Kismet (server) crashed while loading a plugin...\n" "Plugin loading: %s\n\n" "This is either a bug in the plugin, or the plugin needs to be recompiled\n" "to match the version of Kismet you are using (especially if you are using\n" "development versions of Kismet or have recently upgraded.\n\n" "Remove the plugin from the plugins directory, or start Kismet with \n" "plugins disabled (--no-plugins)\n\n", global_plugin_load.c_str()); exit(1); } int Plugintracker::ActivatePlugins() { #ifdef SYS_CYGWIN _sig_func_ptr old_segv = SIG_DFL; #else sig_t old_segv = SIG_DFL; #endif // Try to activate all the plugins for (unsigned int x = 0; x < plugin_vec.size(); x++) { // Try to DLOPEN anything that isn't open if (plugin_vec[x]->dlfileptr == NULL) { global_plugin_load = plugin_vec[x]->filename; old_segv = signal(SIGSEGV, PluginServerSignalHandler); if ((plugin_vec[x]->dlfileptr = dlopen(plugin_vec[x]->filename.c_str(), RTLD_LAZY)) == NULL) { _MSG("Failed to open plugin '"+ plugin_vec[x]->filename + "': " + dlerror(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; signal(SIGSEGV, old_segv); return -1; } // Resolve the version function plugin_revisioncall vsym = NULL; if ((vsym = (plugin_revisioncall) dlsym(plugin_vec[x]->dlfileptr, "kis_revision_info")) == NULL) { _MSG("Failed to find a Kismet version record in plugin '" + plugin_vec[x]->objectname + "'. This plugin has not been " "updated to use the new version API. Please download the " "latest version, or contact the plugin authors. Kismet will " "still load this plugin, but BE WARNED, there is no way " "to know if it was compiled for this version of Kismet, and " "crashes may occur.", MSGFLAG_ERROR); } else { // Make a struct of whatever PREV we use, it will tell us what // it supports in response. plugin_revision *prev = new plugin_revision; prev->version_api_revision = KIS_PLUGINTRACKER_VREVISION; (*vsym)(prev); if (prev->version_api_revision >= 1) { if (prev->major != string(VERSION_MAJOR) || prev->minor != string(VERSION_MINOR) || prev->tiny != string(VERSION_TINY)) { _MSG("Failed to load plugin '" + plugin_vec[x]->objectname + "': This plugin was compiled for a different version of " "Kismet; Please recompile and reinstall it, or remove " "it entirely.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; signal(SIGSEGV, old_segv); return -1; } } delete(prev); } // resolve the info function if ((plugin_vec[x]->infosym = (plugin_infocall) dlsym(plugin_vec[x]->dlfileptr, "kis_plugin_info")) == NULL) { _MSG("Failed to find 'kis_plugin_info' function in plugin '" + plugin_vec[x]->objectname + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; signal(SIGSEGV, old_segv); return -1; } // Fetch the info int ret; ret = (*(plugin_vec[x]->infosym))(&(plugin_vec[x]->usrdata)); if (ret < 0) { _MSG("Failed to fetch info from plugin '" + plugin_vec[x]->objectname + "'", MSGFLAG_FATAL); globalreg->fatal_condition = 1; signal(SIGSEGV, old_segv); return -1; } _MSG("Loaded info for plugin '" + plugin_vec[x]->objectname + "': " "Plugin name: '" + plugin_vec[x]->usrdata.pl_name + "' " "Plugin version: '" + plugin_vec[x]->usrdata.pl_version + "' " "Plugin description: '" + plugin_vec[x]->usrdata.pl_description + "'", MSGFLAG_INFO); } // Run the activate function int ret; if (plugin_vec[x]->usrdata.plugin_register == NULL || plugin_vec[x]->activate == 1) continue; ret = (*(plugin_vec[x]->usrdata.plugin_register))(globalreg); if (ret < 0) { _MSG("Failed to activate plugin '" + plugin_vec[x]->filename + "'", MSGFLAG_FATAL); globalreg->fatal_condition = 1; signal(SIGSEGV, old_segv); return -1; } else if (ret > 0) { _MSG("Activated plugin '" + plugin_vec[x]->filename + "': " "'" + plugin_vec[x]->usrdata.pl_name + "' " "'" + plugin_vec[x]->usrdata.pl_version + "' ", MSGFLAG_INFO); plugin_vec[x]->activate = 1; } signal(SIGSEGV, old_segv); } return 1; } int Plugintracker::LastChancePlugins() { if (ActivatePlugins() < 0 || globalreg->fatal_condition) { globalreg->fatal_condition = 1; return -1; } for (unsigned int x = 0; x < plugin_vec.size(); x++) { if (plugin_vec[x]->activate == 0) { _MSG("Plugin '" + plugin_vec[x]->filename + "' never activated even " "though it responded to the request for plugin information. This " "plugin has problems and can not be loaded.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } return 1; } int Plugintracker::ShutdownPlugins() { _MSG("Shutting down plugins...", MSGFLAG_INFO); for (unsigned int x = 0; x < plugin_vec.size(); x++) { if (plugin_vec[x]->activate == 0 || plugin_vec[x]->usrdata.plugin_unregister == NULL) continue; (*(plugin_vec[x]->usrdata.plugin_unregister))(globalreg); dlclose(plugin_vec[x]->dlfileptr); } // again inefficient, but it only happens once for (unsigned int x = 0; x < plugin_vec.size(); x++) { delete plugin_vec[x]; } plugin_vec.clear(); return 0; } int Plugintracker::BlitPlugins(int in_fd) { for (unsigned int x = 0; x < plugin_vec.size(); x++) { kis_protocol_cache cache; globalreg->kisnetserver->SendToClient(in_fd, plugins_protoref, (void *) plugin_vec[x], &cache); } return 1; } kismet-2013-03-R1b/kis_netframe.cc0000664000175000017500000010520612124602454016435 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "util.h" #include "configfile.h" #include "packet.h" #include "packetsourcetracker.h" #include "packetchain.h" #include "kis_netframe.h" #include "tcpserver.h" #include "getopt.h" #include "dumpfile.h" const char *KISMET_fields_text[] = { "version", "starttime", "servername", "dumpfiles", "uid", NULL }; const char *ERROR_fields_text[] = { "cmdid", "text", NULL }; const char *ACK_fields_text[] = { "cmdid", "text", NULL }; const char *PROTOCOLS_fields_text[] = { "protocols", NULL }; const char *TERMINATE_fields_text[] = { "text", NULL }; const char *CAPABILITY_fields_text[] = { "capabilities", NULL }; const char *TIME_fields_text[] = { "timesec", NULL }; const char *STATUS_fields_text[] = { "text", "flags", NULL }; const char *PACKET_fields_text[] = { "type", "subtype", "timesec", "encrypted", "weak", "beaconrate", "sourcemac", "destmac", "bssid", "ssid", "prototype", "sourceip", "destip", "sourceport", "destport", "nbtype", "nbsource", "sourcename", NULL }; // Kismet welcome printer. Data should be KISMET_data int Protocol_KISMET(PROTO_PARMS) { KISMET_data *kdata = (KISMET_data *) data; ostringstream osstr; for (unsigned int x = 0; x < field_vec->size(); x++) { switch ((KISMET_fields) (*field_vec)[x]) { case KISMET_version: out_string += kdata->version; break; case KISMET_starttime: out_string += kdata->starttime; break; case KISMET_servername: out_string += "\001" + kdata->servername + "\001"; break; case KISMET_dumpfiles: out_string += "\001"; for (unsigned int y = 0; y < globalreg->subsys_dumpfile_vec.size(); y++) { out_string += globalreg->subsys_dumpfile_vec[y]->FetchFileType(); if (y != globalreg->subsys_dumpfile_vec.size() - 1) out_string += ","; } out_string += "\001"; break; case KISMET_uid: osstr << (int) kdata->uid; out_string += osstr.str(); break; default: out_string = "Unknown field requested."; return -1; break; } out_string += " "; } return 1; } // Our own internal capabilities printer - we completely ignore the field vec because // theres only one field that we can print out. This expects the data pointer to be a // pointer to the server protocol map // *PROTOCOLS:123: ALERT,KISMET,NETWORK,CLIENT,... int Protocol_PROTOCOLS(PROTO_PARMS) { map *srvmap = (map *) data; for (map::iterator x = srvmap->begin(); x != srvmap->end(); ++x) { out_string += x->second->header + ","; } out_string = out_string.substr(0, out_string.length() - 1); return 1; } // Our second internal capabilities printer - generate a line of valid fields for a // protocol. This expects the data pointer to be a pointer to a server_protocol record. // *CAPABILITY:123: NETWORK bssid,packets,crypt,weak,... int Protocol_CAPABILITY(PROTO_PARMS) { KisNetFramework::server_protocol *proto = (KisNetFramework::server_protocol *) data; out_string = proto->header + " "; for (unsigned int x = 0; x < proto->field_vec.size(); x++) { out_string += proto->field_vec[x] + ","; } out_string = out_string.substr(0, out_string.length() - 1); return 1; } // We don't care about fields. Data = string int Protocol_TERMINATE(PROTO_PARMS) { string *str = (string *) data; out_string += *str; return 1; } // We don't care about fields. Data = string int Protocol_ERROR(PROTO_PARMS) { CLIRESP_data *rdata = (CLIRESP_data *) data; char dig[10]; for (unsigned int x = 0; x < field_vec->size(); x++) { switch ((ERROR_fields) (*field_vec)[x]) { case ERROR_cmdid: snprintf(dig, 10, "%d", rdata->cmdid); out_string += dig; break; case ERROR_cmdtext: out_string += "\001" + rdata->resptext + "\001"; break; default: out_string = "Unknown field requested."; return -1; break; } out_string += " "; } return 1; } // We don't care about fields. Data = int int Protocol_ACK(PROTO_PARMS) { CLIRESP_data *rdata = (CLIRESP_data *) data; char dig[10]; for (unsigned int x = 0; x < field_vec->size(); x++) { switch ((ACK_fields) (*field_vec)[x]) { case ACK_cmdid: snprintf(dig, 10, "%d", rdata->cmdid); out_string += dig; break; case ACK_cmdtext: out_string += "\001" + rdata->resptext + "\001"; break; default: out_string = "Unknown field requested."; return -1; break; } out_string += " "; } return 1; } // Time printer. We don't care about the fields since we only have one thing to // print out. Data = int int Protocol_TIME(PROTO_PARMS) { char tmpstr[32]; int *tim = (int *) data; snprintf(tmpstr, 32, "%d", *tim); out_string += tmpstr; return 1; } // We don't care about fields. Data = string int Protocol_STATUS(PROTO_PARMS) { STATUS_data *rdata = (STATUS_data *) data; char dig[10]; for (unsigned int x = 0; x < field_vec->size(); x++) { switch ((STATUS_fields) (*field_vec)[x]) { case STATUS_flags: snprintf(dig, 10, "%d", rdata->flags); out_string += dig; break; case STATUS_text: out_string += "\001" + rdata->text + "\001"; break; default: out_string = "\001Unknown field requested.\001"; return -1; break; } out_string += " "; } return 1; } void Protocol_Packet2Data(const kis_packet *info, PACKET_data *data) { // Broken for now #if 0 char tmpstr[128]; // Reserve data->pdvec.reserve(10); snprintf(tmpstr, 128, "%d", (int) info->type); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", (int) info->subtype); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", (int) info->ts.tv_sec); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", info->encrypted); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", info->interesting); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", info->beacon); data->pdvec.push_back(tmpstr); data->pdvec.push_back(info->source_mac.Mac2String()); data->pdvec.push_back(info->dest_mac.Mac2String()); data->pdvec.push_back(info->bssid_mac.Mac2String()); snprintf(tmpstr, 128, "\001%s\001", strlen(info->ssid) == 0 ? " " : info->ssid); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", (int) info->proto.type); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%hd.%hd.%hd.%hd", info->proto.source_ip[0], info->proto.source_ip[1], info->proto.source_ip[2], info->proto.source_ip[3]); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%hd.%hd.%hd.%hd", info->proto.dest_ip[0], info->proto.dest_ip[1], info->proto.dest_ip[2], info->proto.dest_ip[3]); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", info->proto.sport); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", info->proto.dport); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "%d", (int) info->proto.nbtype); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "\001%s\001", strlen(info->proto.netbios_source) == 0 ? " " : info->proto.netbios_source); data->pdvec.push_back(tmpstr); snprintf(tmpstr, 128, "\001%s\001", strlen(info->sourcename) == 0 ? " " : info->sourcename); data->pdvec.push_back(tmpstr); #endif } // packet records. data = PACKET_data int Protocol_PACKET(PROTO_PARMS) { PACKET_data *pdata = (PACKET_data *) data; for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= pdata->pdvec.size()) { out_string = "Unknown field requested."; return -1; } else { out_string += pdata->pdvec[fnum] + " "; } } return 1; } // Client commands int Clicmd_CAPABILITY(CLIENT_PARMS) { // We don't have to do any funny parsing so we can take advantage of being // given the preparsed stuff int cmdref; if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal capability request"); return -1; } if ((cmdref = globalreg->kisnetserver->FetchProtocolRef(((*parsedcmdline)[0]).word)) < 0) { snprintf(errstr, 1024, "Unknown protocol: '%s'", ((*parsedcmdline)[0]).word.c_str()); return -1; } KisNetFramework::server_protocol *prot; if ((prot = globalreg->kisnetserver->FetchProtocol(cmdref)) == NULL) { snprintf(errstr, 1024, "Unable to fetch protocol info"); return -1; } globalreg->kisnetserver->SendToClient(in_clid, globalreg->netproto_map[PROTO_REF_CAPABILITY], (void *) prot, NULL); return 1; } int Clicmd_ENABLE(CLIENT_PARMS) { // We don't have to do any funny parsing so we can take advantage of being // given the preparsed stuff int cmdref; if (parsedcmdline->size() < 2) { snprintf(errstr, 1024, "Illegal enable request"); return -1; } if ((cmdref = globalreg->kisnetserver->FetchProtocolRef(((*parsedcmdline)[0]).word)) < 0) { snprintf(errstr, 1024, "Unknown protocol: '%s'", ((*parsedcmdline)[0]).word.c_str()); return -1; } KisNetFramework::server_protocol *prot; if ((prot = globalreg->kisnetserver->FetchProtocol(cmdref)) == NULL) { snprintf(errstr, 1024, "Unable to fetch protocol info"); return -1; } vector numericf; // Match * - Rough match, good enough for me to just do the first character, // if this becomes a problem sometime come back to it and do it a better way if (((*parsedcmdline)[1]).word[0] == '*') { for (unsigned int x = 0; x < prot->field_vec.size(); x++) { numericf.push_back(x); } } else { vector field_vec = StrTokenize(((*parsedcmdline)[1]).word, ","); for (unsigned int x = 0; x < field_vec.size(); x++) { map::iterator fitr = prot->field_map.find(StrLower(field_vec[x])); if (fitr == prot->field_map.end()) { snprintf(errstr, 1024, "Unknown field %s", field_vec[x].c_str()); return -1; } numericf.push_back(fitr->second); } } globalreg->kisnetserver->AddProtocolClient(in_clid, cmdref, numericf); if (prot->enable != NULL) (*prot->enable)(in_clid, globalreg, prot->auxptr); return 1; } int Clicmd_REMOVE(CLIENT_PARMS) { // We don't have to do any funny parsing so we can take advantage of being // given the preparsed stuff int cmdref; if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal remove request"); return -1; } if ((cmdref = globalreg->kisnetserver->FetchProtocolRef(((*parsedcmdline)[0]).word)) < 0) { snprintf(errstr, 1024, "Unknown protocol: '%s'", ((*parsedcmdline)[0]).word.c_str()); return -1; } // Just nuke it from us entirely globalreg->kisnetserver->DelProtocolClient(in_clid, cmdref); return 1; } void KisNetframe_MessageClient::ProcessMessage(string in_msg, int in_flags) { // Local messages and alerts don't go out to the world. Alerts are sent via // the ALERT protocol. if ((in_flags & MSGFLAG_LOCAL) || (in_flags & MSGFLAG_ALERT)) return; STATUS_data sdata; sdata.text = in_msg; sdata.flags = in_flags; // Dispatch it out to the clients ((KisNetFramework *) auxptr)->SendToAll(_NPM(PROTO_REF_STATUS), (void *) &sdata); } int KisNetFrame_TimeEvent(Timetracker::timer_event *evt, void *parm, GlobalRegistry *globalreg) { // We'll just assume we'll never fail here and that the TIME protocol // always exists. If this isn't the case, we'll fail horribly. time_t curtime = time(0); globalreg->kisnetserver->SendToAll(globalreg->netproto_map[PROTO_REF_TIME], (void *) &curtime); return 1; } KisNetFramework::KisNetFramework() { fprintf(stderr, "FATAL OOPS: KisNetFramework() called with no globalreg\n"); exit(1); } void KisNetFramework::Usage(char *name) { printf(" *** Kismet Client/Server Options ***\n"); printf(" -l, --server-listen Override Kismet server listen options\n"); } KisNetFramework::KisNetFramework(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; netserver = NULL; int port = 0, maxcli = 0; char srv_proto[11], srv_bindhost[129]; TcpServer *tcpsrv; string listenline; next_netprotoref = 0; valid = 0; // Sanity check for timetracker if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: KisNetFramework called without timetracker\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: KisNetFramework called without kismet_config\n"); exit(1); } if (globalreg->messagebus == NULL) { fprintf(stderr, "FATAL OOPS: KisNetFramework called without messagebus\n"); exit(1); } // Commandline stuff static struct option netframe_long_options[] = { { "server-listen", required_argument, 0, 'l' }, { 0, 0, 0, 0 } }; int option_idx = 0; // Hack the extern getopt index optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-l:", netframe_long_options, &option_idx); if (r < 0) break; switch (r) { case 'l': listenline = string(optarg); break; } } // Parse the config file and get the protocol and port info... ah, abusing // evaluation shortcuts if (listenline.length() == 0 && (listenline = globalreg->kismet_config->FetchOpt("listen")) == "") { _MSG("No 'listen' config line defined for the Kismet UI server; This " "usually means you have not upgraded your Kismet config file. Copy " "the config file from the source directory and replace your " "current kismet.conf (Or specify the new config file manually)", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (sscanf(listenline.c_str(), "%10[^:]://%128[^:]:%d", srv_proto, srv_bindhost, &port) != 3) { _MSG("Malformed 'listen' config line defined for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("maxclients") == "") { _MSG("No 'maxclients' config line defined for the Kismet UI server, " "defaulting to 5 clients.", MSGFLAG_INFO); maxcli = 5; } else if (sscanf(globalreg->kismet_config->FetchOpt("maxclients").c_str(), "%d", &maxcli) != 1) { _MSG("Malformed 'maxclients' config line defined for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("maxbacklog") == "") { _MSG("No 'maxbacklog' config line defined for the Kismet UI server, " "defaulting to 5000 lines", MSGFLAG_INFO); maxbacklog = 5000; } else if (sscanf(globalreg->kismet_config->FetchOpt("maxbacklog").c_str(), "%d", &maxbacklog) != 1) { _MSG("Malformed 'maxbacklog' config line defined for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("allowedhosts") == "") { _MSG("No 'allowedhosts' config line defined for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } // We only know how to set up a tcp server right now if (strncasecmp(srv_proto, "tcp", 10) == 0) { tcpsrv = new TcpServer(globalreg); tcpsrv->SetupServer(port, maxcli, srv_bindhost, globalreg->kismet_config->FetchOpt("allowedhosts")); netserver = tcpsrv; server_type = 0; } else { server_type = -1; _MSG("Invalid protocol in 'listen' config line for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } // Register the core Kismet protocols // Protocols we REQUIRE all clients to support globalreg->netproto_map[PROTO_REF_KISMET] = RegisterProtocol("KISMET", 1, 0, KISMET_fields_text, &Protocol_KISMET, NULL, NULL); globalreg->netproto_map[PROTO_REF_ERROR] = RegisterProtocol("ERROR", 1, 0, ERROR_fields_text, &Protocol_ERROR, NULL, NULL); globalreg->netproto_map[PROTO_REF_ACK] = RegisterProtocol("ACK", 1, 0, ACK_fields_text, &Protocol_ACK, NULL, NULL); globalreg->netproto_map[PROTO_REF_PROTOCOL] = RegisterProtocol("PROTOCOLS", 1, 0, PROTOCOLS_fields_text, &Protocol_PROTOCOLS, NULL, NULL); globalreg->netproto_map[PROTO_REF_CAPABILITY] = RegisterProtocol("CAPABILITY", 1, 0, CAPABILITY_fields_text, &Protocol_CAPABILITY, NULL, NULL); globalreg->netproto_map[PROTO_REF_TERMINATE] = RegisterProtocol("TERMINATE", 1, 0, TERMINATE_fields_text, &Protocol_TERMINATE, NULL, NULL); globalreg->netproto_map[PROTO_REF_TIME] = RegisterProtocol("TIME", 1, 0, TIME_fields_text, &Protocol_TIME, NULL, NULL); // Other protocols globalreg->netproto_map[PROTO_REF_PACKET] = RegisterProtocol("PACKET", 0, 0, PACKET_fields_text, &Protocol_PACKET, NULL, NULL); globalreg->netproto_map[PROTO_REF_STATUS] = RegisterProtocol("STATUS", 0, 0, STATUS_fields_text, &Protocol_STATUS, NULL, NULL); // Create the message bus attachment to forward messages to the client kisnet_msgcli = new KisNetframe_MessageClient(globalreg, this); globalreg->messagebus->RegisterClient(kisnet_msgcli, MSGFLAG_ALL); // Kismet builtin client commands RegisterClientCommand("CAPABILITY", &Clicmd_CAPABILITY, NULL); RegisterClientCommand("ENABLE", &Clicmd_ENABLE, NULL); RegisterClientCommand("REMOVE", &Clicmd_REMOVE, NULL); // Register timer events globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &KisNetFrame_TimeEvent, NULL); valid = 1; } int KisNetFramework::Activate() { if (server_type != 0) { _MSG("KisNetFramework unknown server type, something didn't initialize", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if (netserver->EnableServer() < 0 || globalreg->fatal_condition) { _MSG("Failed to enable TCP listener for the Kismet UI server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } netserver->RegisterServerFramework(this); return 1; } KisNetFramework::~KisNetFramework() { // Remove our message handler globalreg->messagebus->RemoveClient(kisnet_msgcli); } int KisNetFramework::Accept(int in_fd) { // Create their options client_opt *opt = new client_opt; client_optmap[in_fd] = opt; char temp[512]; // Set the mandatory sentences. We don't have to do error checking here because // it can't exist in the required vector if it isn't registered. for (unsigned int reqprot = 0; reqprot < required_protocols.size(); reqprot++) { int tref = required_protocols[reqprot]; vector reqfields; map::iterator spitr = protocol_map.find(tref); for (unsigned int fnum = 0; fnum < spitr->second->field_vec.size(); fnum++) { reqfields.push_back(fnum); } AddProtocolClient(in_fd, tref, reqfields); } // Send the mandatory stuff like the Kismet info KISMET_data kdat; kdat.version = "0.0.0"; snprintf(temp, 512, "%u", (unsigned int) globalreg->start_time); kdat.starttime = string(temp); kdat.servername = globalreg->servername; kdat.timestamp = "0"; kdat.newversion = globalreg->version_major + string(",") + globalreg->version_minor + string(",") + globalreg->version_tiny; kdat.uid = geteuid(); SendToClient(in_fd, globalreg->netproto_map[PROTO_REF_KISMET], (void *) &kdat, NULL); // Protocols SendToClient(in_fd, globalreg->netproto_map[PROTO_REF_PROTOCOL], (void *) &protocol_map, NULL); _MSG("Kismet server accepted connection from " + netserver->GetRemoteAddr(in_fd), MSGFLAG_INFO); return 1; } int KisNetFramework::BufferDrained(int in_fd) { map::iterator opitr = client_optmap.find(in_fd); if (opitr == client_optmap.end()) { snprintf(errstr, 1024, "KisNetFramework::SendToClient illegal client %d.", in_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } client_opt *opt = opitr->second; int ret = 0; if (opt->backlog.size() == 0) return 0; while (opt->backlog.size() > 0) { string outtext = opt->backlog[0]; ret = netserver->WriteData(in_fd, (uint8_t *) outtext.c_str(), outtext.length()); // Catch "full buffer" error and stop trying to shove more down it if (ret == -2) return 0; if (ret < 0) return ret; opt->backlog.erase(opt->backlog.begin()); if (opt->backlog.size() == 0) { snprintf(errstr, 1024, "Flushed protocol data backlog for Kismet " "client %d", in_fd); _MSG(errstr, (MSGFLAG_LOCAL | MSGFLAG_ERROR)); } } return 1; } int KisNetFramework::ParseData(int in_fd) { int len, rlen; char *buf; string strbuf; len = netserver->FetchReadLen(in_fd); buf = new char[len + 1]; if (netserver->ReadData(in_fd, buf, len, &rlen) < 0) { globalreg->messagebus->InjectMessage("KisNetFramework::ParseData failed to " "fetch data from the client.", MSGFLAG_ERROR); return -1; } buf[len] = '\0'; // Parse without including partials, so we don't get a fragmented command // out of the buffer vector inptok = StrTokenize(buf, "\n", 0); delete[] buf; // Bail on no useful data if (inptok.size() < 1) { return 0; } for (unsigned int it = 0; it < inptok.size(); it++) { // No matter what we've dealt with this data block netserver->MarkRead(in_fd, inptok[it].length() + 1); // Handle funny trailing stuff from telnet and some other clients if (inptok[it][inptok[it].length() - 1] == '\r') { inptok[it] = inptok[it].substr(0, inptok[it].length() - 1); } vector cmdtoks = NetStrTokenize(inptok[it], " "); if (cmdtoks.size() < 2) { // Silently fail since there wasn't enough to deal with it continue; } int cmdid; if (sscanf(cmdtoks[0].word.c_str(), "!%d", &cmdid) != 1) { // Silently fail if we can't figure out how to generate the error, again continue; } // Nuke the first element of the command tokens (we just pulled it off to // get the cmdid) cmdtoks.erase(cmdtoks.begin()); // Find a command function to deal with this protocol CLIRESP_data rdat; rdat.cmdid = cmdid; map::iterator ccitr = client_cmd_map.find(StrLower(cmdtoks[0].word)); if (ccitr != client_cmd_map.end()) { // Nuke the first word again - we just pulled it off to get the command // fprintf(stderr, "debug - ctoks '%s' %u %u %u\n", cmdtoks[0].word.c_str(), cmdtoks.size(), cmdtoks[0].end, inptok[it].length()); cmdtoks.erase(cmdtoks.begin()); // fprintf(stderr, "debug - fullcmd '%s' %u %u %u\n", cmdtoks[0].word.c_str(), cmdtoks.size(), cmdtoks[0].end, inptok[it].length()); string fullcmd = inptok[it].substr(cmdtoks[0].end, (inptok[it].length() - cmdtoks[0].end)); // Call the processor and return error conditions and ack if ((*ccitr->second->cmd) (in_fd, this, globalreg, errstr, fullcmd, &cmdtoks, ccitr->second->auxptr) < 0) { rdat.resptext = string(errstr); SendToClient(in_fd, globalreg->netproto_map[PROTO_REF_ERROR], (void *) &rdat, NULL); _MSG("Failed Kismet client command: " + rdat.resptext, MSGFLAG_ERROR); } else { rdat.resptext = string("OK"); SendToClient(in_fd, globalreg->netproto_map[PROTO_REF_ACK], (void *) &rdat, NULL); } } else { rdat.resptext = string("NO SUCH COMMAND"); SendToClient(in_fd, globalreg->netproto_map[PROTO_REF_ERROR], (void *) &rdat, NULL); } } return 1; } int KisNetFramework::KillConnection(int in_fd) { // Do a little testing here since we might not have an opt record map::iterator citr = client_optmap.find(in_fd); if (citr != client_optmap.end()) { // Remove all our protocols map >::iterator clpitr; while ((clpitr = citr->second->protocols.begin()) != citr->second->protocols.end()) { DelProtocolClient(in_fd, clpitr->first); } /* for (map >::iterator clpitr = citr->second->protocols.begin(); clpitr != citr->second->protocols.end(); ++clpitr) DelProtocolClient(in_fd, clpitr->first); */ client_opt *sec = citr->second; client_optmap.erase(citr); delete sec; } return 1; } int KisNetFramework::Shutdown() { return ServerFramework::Shutdown(); } int KisNetFramework::RegisterClientCommand(string in_cmdword, ClientCommand in_cmd, void *in_auxptr) { string lcmd = StrLower(in_cmdword); if (in_cmdword.length() > 16) { snprintf(errstr, 1024, "KisNetFramework::RegisterClientCommand refusing to " "register '%s' as it is greater than 16 characters.", in_cmdword.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } if (client_cmd_map.find(lcmd) != client_cmd_map.end()) { snprintf(errstr, 1024, "KisNetFramework::RegisterClientCommand refusing to " "register command '%s', command already exists.", lcmd.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } client_command_rec *cmdrec = new client_command_rec; cmdrec->cmd = in_cmd; cmdrec->auxptr = in_auxptr; client_cmd_map[lcmd] = cmdrec; return 1; } int KisNetFramework::RemoveClientCommand(string in_cmdword) { if (client_cmd_map.find(in_cmdword) == client_cmd_map.end()) return 0; delete client_cmd_map[in_cmdword]; client_cmd_map.erase(in_cmdword); return 1; } // Create an output string based on the clients // This looks very complex - and it is - but almost all of the "big" ops like // find are done with integer references. They're cheap. // This takes the struct to be sent and pumps it through the dynamic protocol/field // system. int KisNetFramework::SendToClient(int in_fd, int in_refnum, const void *in_data, kis_protocol_cache *in_cache) { // Make sure this is a valid client map::iterator opitr = client_optmap.find(in_fd); if (opitr == client_optmap.end()) { snprintf(errstr, 1024, "KisNetFramework::SendToClient illegal client %d.", in_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } client_opt *opt = opitr->second; // See if this client even handles this protocol... map >::iterator clprotitr = opt->protocols.find(in_refnum); if (clprotitr == opt->protocols.end()) return 0; const vector *fieldlist = &clprotitr->second; // Find this protocol now - we only do this after we're sure we want to print to // it. map::iterator spitr = protocol_map.find(in_refnum); if (spitr == protocol_map.end()) { snprintf(errstr, 1024, "KisNetFramework::SendToClient Protocol %d not " "registered.", in_refnum); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } server_protocol *prot = spitr->second; if (prot->cacheable && in_cache == NULL) { snprintf(errstr, 1024, "KisNetFramework::SendToClient protocol %s " "requires caching but got a NULL cache ref, fix me", prot->header.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } // Bounce through the printer function string fieldtext; if ((*prot->printer)(fieldtext, fieldlist, in_data, prot->auxptr, in_cache, globalreg) == -1) { snprintf(errstr, 1024, "%s", fieldtext.c_str()); return -1; } // Assemble a line for them: // *HEADER: DATA\n // 16 x 1 int ret = 0; // Check the size int blogsz = opt->backlog.size(); // Bail gracefully for now if (blogsz >= maxbacklog) { return 0; } int nlen = prot->header.length() + fieldtext.length() + 5; // *..: \n\0 char *outtext = new char[nlen]; snprintf(outtext, nlen, "*%s: %s\n", prot->header.c_str(), fieldtext.c_str()); // Look in the backlog vector and backlog it if we're already over-full if (blogsz > 0) { opt->backlog.push_back(outtext); delete[] outtext; return 0; } ret = netserver->WriteData(in_fd, (uint8_t *) outtext, strlen(outtext)); // Catch "full buffer" error if (ret == -2) { snprintf(errstr, 1024, "Client %d ring buffer full, storing Kismet protocol " "data in backlog vector", in_fd); _MSG(errstr, (MSGFLAG_LOCAL | MSGFLAG_INFO)); opt->backlog.push_back(outtext); delete[] outtext; return 0; } delete[] outtext; if (ret < 0) return ret; return nlen; } int KisNetFramework::SendToAll(int in_refnum, const void *in_data) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; kis_protocol_cache cache; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendToClient(clvec[x], in_refnum, in_data, &cache) > 0) nsent++; } return nsent; } int KisNetFramework::RegisterProtocol(string in_header, int in_required, int in_cache, const char **in_fields, int (*in_printer)(PROTO_PARMS), void (*in_enable)(PROTO_ENABLE_PARMS), void *in_auxdata) { // First, see if we're already registered and return a -1 if we are. You can't // register a protocol twice. if (FetchProtocolRef(in_header) != -1) { snprintf(errstr, 1024, "KisNetFramework::RegisterProtocol refusing to " "register '%s' as it is already a registered protocol.", in_header.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } if (in_header.length() > 16) { snprintf(errstr, 1024, "KisNetFramework::RegisterProtocol refusing to " "register '%s' as it is greater than 16 characters.", in_header.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } int refnum = next_netprotoref++; server_protocol *sen = new server_protocol; sen->ref_index = refnum; sen->header = in_header; int x = 0; while (in_fields[x] != NULL) { sen->field_map[in_fields[x]] = x; sen->field_vec.push_back(in_fields[x]); x++; } sen->printer = in_printer; sen->enable = in_enable; sen->required = in_required; sen->cacheable = in_cache; sen->auxptr = in_auxdata; // Put us in the map protocol_map[refnum] = sen; ref_map[StrLower(in_header)] = refnum; if (in_required) required_protocols.push_back(refnum); return refnum; } int KisNetFramework::RemoveProtocol(int in_protoref) { // Efficiency isn't the biggest deal here since it happens rarely if (in_protoref < 0) return 0; if (protocol_map.find(in_protoref) == protocol_map.end()) return 0; string cmdheader = protocol_map[in_protoref]->header; delete protocol_map[in_protoref]; protocol_map.erase(in_protoref); ref_map.erase(cmdheader); for (unsigned int x = 0; x < required_protocols.size(); x++) { if (required_protocols[x] == in_protoref) { required_protocols.erase(required_protocols.begin() + x); break; } } return 1; } int KisNetFramework::FetchProtocolRef(string in_header) { map::iterator rmitr = ref_map.find(StrLower(in_header)); if (rmitr == ref_map.end()) return -1; return rmitr->second; } KisNetFramework::server_protocol *KisNetFramework::FetchProtocol(int in_ref) { KisNetFramework::server_protocol *ret = NULL; map::iterator spi = protocol_map.find(in_ref); if (spi != protocol_map.end()) ret = spi->second; return ret; } int KisNetFramework::FetchNumClientRefs(int in_refnum) { map::iterator cmpitr = client_mapped_protocols.find(in_refnum); if (cmpitr != client_mapped_protocols.end()) return cmpitr->second; return 0; } int KisNetFramework::FetchNumClients() { return netserver->FetchNumClients(); } void KisNetFramework::AddProtocolClient(int in_fd, int in_refnum, vector in_fields) { map::iterator citr = client_optmap.find(in_fd); if (citr == client_optmap.end()) { return; } // Find out if it already exists and increment the use count if it does map >::iterator clpitr = citr->second->protocols.find(in_refnum); if (clpitr == citr->second->protocols.end()) client_mapped_protocols[in_refnum]++; citr->second->protocols[in_refnum] = in_fields; } void KisNetFramework::DelProtocolClient(int in_fd, int in_refnum) { map::iterator citr = client_optmap.find(in_fd); if (citr == client_optmap.end()) return; map >::iterator clpitr = citr->second->protocols.find(in_refnum); if (clpitr != citr->second->protocols.end()) { citr->second->protocols.erase(clpitr); client_mapped_protocols[in_refnum]--; } } kismet-2013-03-R1b/packetsource_pcap.h0000664000175000017500000001736512124602454017333 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * pcapsource handes the largest number of card types. ideally, everything * should be part of pcapsource so that different tools can use them * besides kismet. * * pcapsource encompasses multiple methods of entering monitor mode and * multiple link encapsulation types, the only underlying consistency * is the use of libpcap to fetch frames. * */ #ifndef __PACKETSOURCE_PCAP_H__ #define __PACKETSOURCE_PCAP_H__ #include "config.h" #ifdef HAVE_LIBPCAP #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "ifcontrol.h" extern "C" { #ifndef HAVE_PCAPPCAP_H #include #else #include #endif } #include "kis_ppi.h" // Include the various variations of BSD radiotap headers from the system if // we can get them, incidentally pull in other stuff but I'm not sure whats // needed so we'll leave the extra headers for now #ifdef HAVE_BSD_SYS_RADIOTAP #include #include #include #if defined(SYS_OPENBSD) || defined(SYS_NETBSD) #include #include #include #include #include #include #endif // Open/Net #ifdef SYS_FREEBSD #include #include #endif // FreeBSD #endif // BSD radiotap // Include the linux system radiotap headers #ifdef HAVE_LINUX_SYS_RADIOTAP #include #endif // If we couldn't make any sense of system rt headers (OSX perhaps, or // win32, or an older linux) then pull in the local radiotap copy #ifdef HAVE_LOCAL_RADIOTAP #include "local_ieee80211_radiotap.h" #endif // We provide the pcap packet sources #define USE_PACKETSOURCE_PCAPFILE // Maximum SSID length for storing #define MAX_STORED_SSID 32 // for DLT_PRISM_HEADER #define WLAN_DEVNAMELEN_MAX 16 // Define linktype headers if we don't have them in our includes for some // reason #ifndef DLT_PRISM_HEADER #define DLT_PRISM_HEADER 119 #endif #ifndef DLT_IEEE802_11 #define DLT_IEEE802_11 105 #endif #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 #endif #ifndef DLT_IEEE802_11_RADIO_AVS #define DLT_IEEE802_11_RADIO_AVS 163 #endif // Define kluged local linktype for BSD lame-mode #define KDLT_BSD802_11 -100 // Extension to radiotap header not yet included in all BSD's #ifndef IEEE80211_RADIOTAP_F_FCS #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #endif #ifndef IEEE80211_IOC_CHANNEL #define IEEE80211_IOC_CHANNEL 0 #endif // Prism 802.11 headers from wlan-ng tacked on to the beginning of a // pcap packet... Snagged from the wlan-ng source typedef struct { uint32_t did; uint16_t status; uint16_t len; uint32_t data; } __attribute__((__packed__)) p80211item_uint32_t; typedef struct { uint32_t msgcode; uint32_t msglen; uint8_t devname[WLAN_DEVNAMELEN_MAX]; p80211item_uint32_t hosttime; p80211item_uint32_t mactime; p80211item_uint32_t channel; p80211item_uint32_t rssi; p80211item_uint32_t sq; p80211item_uint32_t signal; p80211item_uint32_t noise; p80211item_uint32_t rate; p80211item_uint32_t istx; p80211item_uint32_t frmlen; } __attribute__((__packed__)) wlan_ng_prism2_header; // wlan-ng (and hopefully others) AVS header, version one. Fields in // network byte order. typedef struct { uint32_t version; uint32_t length; uint64_t mactime; uint64_t hosttime; uint32_t phytype; uint32_t channel; uint32_t datarate; uint32_t antenna; uint32_t priority; uint32_t ssi_type; int32_t ssi_signal; int32_t ssi_noise; uint32_t preamble; uint32_t encoding; } avs_80211_1_header; class PacketSource_Pcap : public KisPacketSource { public: PacketSource_Pcap() { fprintf(stderr, "FATAL OOPS: Packetsource_Pcap() called\n"); exit(1); } PacketSource_Pcap(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } // No creation or probe for this high-level metasource virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) = 0; virtual int AutotypeProbe(string in_device) = 0; virtual int RegisterSources(Packetsourcetracker *tracker) = 0; PacketSource_Pcap(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { pd = NULL; override_dlt = -1; } virtual ~PacketSource_Pcap() { } // No management functions at this level virtual int EnableMonitor() = 0; virtual int DisableMonitor() = 0; virtual int FetchChannelCapable() = 0; virtual int SetChannel(unsigned int in_ch) = 0; // We expect to be drive by the child IPC virtual int ChildIPCControl() { return 1; } virtual int OpenSource(); virtual int CloseSource(); virtual int FetchDescriptor(); virtual int Poll(); static void Pcap_Callback(u_char *bp, const struct pcap_pkthdr *header, const u_char *in_data); virtual int FetchHardwareChannel(); // Mangle linkheaders off a frame, etc virtual int ManglePacket(kis_packet *packet, kis_datachunk *linkchunk); protected: // Parse the data link type virtual int DatalinkType(); // Mangle Prism2 and AVS frames int Prism2KisPack(kis_packet *packet, kis_datachunk *linkchunk); // If we have radiotap headers, mangle those into kis packets int Radiotap2KisPack(kis_packet *packet, kis_datachunk *linkchunk); // If we're just a straight up frame int Eight2KisPack(kis_packet *packet, kis_datachunk *linkchunk); // Cace PPI int PPI2KisPack(kis_packet *packet, kis_datachunk *linkchunk); pcap_t *pd; int datalink_type; int override_dlt; }; class PacketSource_Pcapfile : public PacketSource_Pcap { public: PacketSource_Pcapfile() { fprintf(stderr, "FATAL OOPS: Packetsource_Pcapfile() called\n"); exit(1); } PacketSource_Pcapfile(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } // This should return a new object of its own subclass type virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Pcapfile(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Pcapfile(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { // Foo } virtual ~PacketSource_Pcapfile() { } virtual int OpenSource(); virtual int Poll(); virtual int FetchChannelCapable() { return 0; } // Basically do nothing because they have no meaning virtual int EnableMonitor() { return 0; } virtual int DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_SILENCE; } virtual int SetChannel(unsigned int in_ch) { return 0; } virtual int HopNextChannel() { return 0; } protected: // Do nothing here, we don't have an independent radio data fetch, // we're just filling in the virtual virtual void FetchRadioData(kis_packet *in_packet) { }; }; #endif /* have_libpcap */ #endif kismet-2013-03-R1b/restricted-plugin-ptw/0000775000175000017500000000000012124602454017727 5ustar dragorndragornkismet-2013-03-R1b/restricted-plugin-ptw/aircrack-ptw2-lib.h0000664000175000017500000000467212124602454023326 0ustar dragorndragorn/* * Copyright (c) 2007, Erik Tews, Andrei Pychkine and Ralf-Philipp Weinmann. * */ #ifndef _AIRCRACK_PTW2_H_ #define _AIRCRACK_PTW2_H_ #include // Number of bytes we use for our table of seen IVs, this is (2^24)/8 #define PTW2_IVTABLELEN 2097152 // How many sessions do we use to check if a guessed key is correct // 10 seems to be a reasonable choice // Its now the number of sessions for selecting 10 at a random position #define PTW2_CONTROLSESSIONS 10000 // The maximum possible length of the main key, 13 is the maximum for a 104 bit key #define PTW2_KEYHSBYTES 29 // How long the IV is, 3 is the default value for WEP #define PTW2_IVBYTES 3 // How many bytes of a keystream we collect, 16 are needed for a 104 bit key #define PTW2_KSBYTES 64 // The MAGIC VALUE!! #define PTW2_n 256 // distinguish klein and ptw #define NO_KLEIN 0x01 #define NO_PTW2 0x02 // We use this to keep track of the outputs of A_i typedef struct { // How often the value b appeard as an output of A_i int votes; uint8_t b; } PTW2_tableentry; // A recovered session typedef struct { // The IV used in this session uint8_t iv[PTW2_IVBYTES]; // The keystream used in this session uint8_t keystream[PTW2_KSBYTES]; // Weight for this session int weight[PTW2_KSBYTES]; } PTW2_session; // The state of an attack // You should usually never modify these values manually typedef struct { // How many unique packets or IVs have been collected int packets_collected; // Table to check for duplicate IVs uint8_t seen_iv[PTW2_IVTABLELEN]; // How many sessions for checking a guessed key have been collected int sessions_collected; // The actual recovered sessions PTW2_session sessions[PTW2_CONTROLSESSIONS]; // The table with votes for the keybytesums PTW2_tableentry tablefirst[PTW2_KEYHSBYTES][PTW2_n]; // The table with the votes from the second round PTW2_tableentry tablesecond[PTW2_KEYHSBYTES][PTW2_n]; // Sessions for the original klein attack PTW2_session * allsessions; int allsessions_size; // Length of the key, we are going to attack int keylength; } PTW2_attackstate; PTW2_attackstate * PTW2_newattackstate(); void PTW2_freeattackstate(PTW2_attackstate *); int PTW2_addsession(PTW2_attackstate *, uint8_t *, uint8_t *, uint8_t *, int); int PTW2_computeKey(PTW2_attackstate *, uint8_t *, int, int, int *, int [][PTW2_n], int attacks); PTW2_attackstate *PTW2_copyattackstate(PTW2_attackstate *); #endif kismet-2013-03-R1b/restricted-plugin-ptw/Makefile0000664000175000017500000000165512124602454021376 0ustar dragorndragorn# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ -lssl -lpthread -lcrypto CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC PLUGOBJS = aircrack-crypto.o aircrack-ptw2-lib.o aircrack-kismet.o PLUGOUT = aircrack-kismet.so all: $(PLUGOUT) $(PLUGOUT): $(PLUGOBJS) $(LD) $(PLUGINLDFLAGS) $(PLUGOBJS) -o $(PLUGOUT) $(LIBS) install: $(PLUGOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $^ $(DESTDIR)/$(plugindir)/$^ userinstall: $(PLUGOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) $(PLUGOUT) ${HOME}/.kismet/plugins/$(PLUGOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-kismet.cc0000664000175000017500000004116112124602454023312 0ustar dragorndragorn/* This file is part of Kismet This file was derived directly from aircrack-ng, and most of the other files in this directory come, almost unmodified, from that project. For more information about aircrack-ng, visit: http://aircrack-ng.org Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. * If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. * If you do not wish to do so, delete this exception statement from your version. * If you delete this exception statement from all source files in the program, then also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aircrack-crypto.h" #include "aircrack-ptw2-lib.h" GlobalRegistry *globalreg = NULL; struct kisptw_net { mac_addr bssid; PTW2_attackstate *ptw_clean; PTW2_attackstate *ptw_vague; int last_crack_ivs, last_crack_vivs; int num_ptw_ivs, num_ptw_vivs; int ptw_solved; int ptw_attempt; // Dupes for our thread pthread_t crackthread; // Use a mutex for trylock to tell if we're done, if we can lock it, // we're done pthread_mutex_t crackdone; int threaded; PTW2_attackstate *ptw_clean_t; PTW2_attackstate *ptw_vague_t; int num_ptw_ivs_t, num_ptw_vivs_t; time_t last_packet; int len; uint8_t wepkey[64]; }; struct kisptw_state { map netmap; int timer_ref; int alert_ref; }; kisptw_state *state = NULL; void *kisptw_crack(void *arg) { kisptw_net *pnet = (kisptw_net *) arg; int i, j; int numpackets = 0; /* Clear the thread sigmask so we don't catch sigterm weirdly */ sigset_t sset; sigfillset(&sset); pthread_sigmask(SIG_BLOCK, &sset, NULL); int (* all)[256]; int PTW_DEFAULTBF[PTW2_KEYHSBYTES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; all = (int (*)[256]) alloca(256 * 32 * sizeof(int)); for (i = 0; i < 32; i++) { for (j = 0; j < 256; j++) { all[i][j] = 1; } } if (pnet->num_ptw_ivs_t > 99) { if (PTW2_computeKey(pnet->ptw_clean_t, pnet->wepkey, 5, 1000, PTW_DEFAULTBF, all, 1) == 1) pnet->len = 5; else if (PTW2_computeKey(pnet->ptw_clean_t, pnet->wepkey, 13, (2000000), PTW_DEFAULTBF, all, 1) == 1) pnet->len = 13; else if (PTW2_computeKey(pnet->ptw_clean_t, pnet->wepkey, 5, (100000), PTW_DEFAULTBF, all, 1) == 1) pnet->len = 5; } if (pnet->len == 0 && pnet->num_ptw_vivs_t != 0) { PTW_DEFAULTBF[10] = PTW_DEFAULTBF[11] = 1; if (PTW2_computeKey(pnet->ptw_vague_t, pnet->wepkey, 5, 1000, PTW_DEFAULTBF, all, 1) == 1) pnet->len = 5; else if (PTW2_computeKey(pnet->ptw_vague_t, pnet->wepkey, 13, (2000000), PTW_DEFAULTBF, all, 1) == 1) pnet->len = 13; else if (PTW2_computeKey(pnet->ptw_vague_t, pnet->wepkey, 5, (200000), PTW_DEFAULTBF, all, 1) == 1) pnet->len = 5; } if (pnet->len) { pnet->ptw_solved = 1; } else { pnet->ptw_attempt = 2; } pthread_mutex_unlock(&(pnet->crackdone)); pthread_exit((void *) 0); } int kisptw_event_timer(TIMEEVENT_PARMS) { kisptw_state *kst = (kisptw_state *) parm; for (map::iterator x = kst->netmap.begin(); x != kst->netmap.end(); ++x) { if (globalreg->netracker->GetNetworkTag(x->second->bssid, "WEP-AUTO") != "") { _MSG("Kismet-PTW stopping cracking attempts on the WEP key for " + x->second->bssid.Mac2String() + ": WEP key found via Auto-WEP", MSGFLAG_INFO); x->second->ptw_solved = 1; if (x->second->ptw_clean != NULL) { PTW2_freeattackstate(x->second->ptw_clean); x->second->ptw_clean = NULL; } if (x->second->ptw_clean_t != NULL) { PTW2_freeattackstate(x->second->ptw_clean_t); x->second->ptw_clean_t = NULL; } if (x->second->ptw_vague != NULL) { PTW2_freeattackstate(x->second->ptw_vague); x->second->ptw_vague = NULL; } if (x->second->ptw_vague_t != NULL) { PTW2_freeattackstate(x->second->ptw_vague_t); x->second->ptw_vague_t = NULL; } return 0; } if (x->second->ptw_attempt == 2) { _MSG("Failed to crack WEP key on " + x->second->bssid.Mac2String() + ": " "Not enough data collected yet", MSGFLAG_INFO); x->second->ptw_attempt = 0; } // If we solved this network, we keep the record but free the rest if (x->second->ptw_solved && x->second->ptw_solved < 2) { if (x->second->ptw_clean != NULL) { PTW2_freeattackstate(x->second->ptw_clean); x->second->ptw_clean = NULL; } if (x->second->ptw_clean_t != NULL) { PTW2_freeattackstate(x->second->ptw_clean_t); x->second->ptw_clean_t = NULL; } if (x->second->ptw_vague != NULL) { PTW2_freeattackstate(x->second->ptw_vague); x->second->ptw_vague = NULL; } if (x->second->ptw_vague_t != NULL) { PTW2_freeattackstate(x->second->ptw_vague_t); x->second->ptw_vague_t = NULL; } ostringstream osstr; for (int k = 0; k < x->second->len; k++) { osstr << hex << setfill('0') << setw(2) << (int) x->second->wepkey[k]; } globalreg->netracker->SetNetworkTag(x->second->bssid, "WEP-PTW", osstr.str(), 1); string al = "Cracked WEP key on " + x->second->bssid.Mac2String() + ": " + osstr.str(); globalreg->alertracker->RaiseAlert(state->alert_ref, NULL, x->second->bssid, x->second->bssid, x->second->bssid, x->second->bssid, 0, al); globalreg->builtindissector->AddWepKey(x->second->bssid, x->second->wepkey, x->second->len, 1); _MSG("Cleaned up WEP data on " + x->second->bssid.Mac2String(), MSGFLAG_INFO); x->second->ptw_solved = 2; } if (x->second->threaded) { void *ret; #if 0 if (pthread_tryjoin_np(x->second->crackthread, &ret) == 0) { x->second->threaded = 0; } #endif if (pthread_mutex_trylock(&(x->second->crackdone)) == 0) { x->second->threaded = 0; pthread_mutex_unlock(&(x->second->crackdone)); } } // Reset the vague packet buffer if it gets out of hand if (x->second->num_ptw_vivs > 200000 && x->second->ptw_vague) { x->second->num_ptw_vivs = 0; PTW2_freeattackstate(x->second->ptw_vague); } if (time(0) - x->second->last_packet > 1800 && x->second->last_packet != 0 && x->second->threaded == 0) { _MSG("No packets from " + x->second->bssid.Mac2String() + " for 30 " "minutes, removing PTW WEP cracking data", MSGFLAG_INFO); if (x->second->ptw_clean != NULL) { PTW2_freeattackstate(x->second->ptw_clean); x->second->ptw_clean = NULL; } if (x->second->ptw_clean_t != NULL) { PTW2_freeattackstate(x->second->ptw_clean_t); x->second->ptw_clean_t = NULL; } if (x->second->ptw_vague != NULL) { PTW2_freeattackstate(x->second->ptw_vague); x->second->ptw_vague = NULL; } if (x->second->ptw_vague_t != NULL) { PTW2_freeattackstate(x->second->ptw_vague_t); x->second->ptw_vague_t = NULL; } x->second->last_packet = 0; } if (x->second->ptw_solved == 0 && (x->second->num_ptw_ivs > x->second->last_crack_ivs + 1000 || x->second->num_ptw_vivs > x->second->last_crack_vivs + 5000) && x->second->threaded == 0) { if (x->second->ptw_clean_t) PTW2_freeattackstate(x->second->ptw_clean_t); if (x->second->ptw_vague_t) PTW2_freeattackstate(x->second->ptw_vague_t); x->second->ptw_clean_t = NULL; x->second->ptw_vague_t = NULL; x->second->ptw_clean_t = PTW2_copyattackstate(x->second->ptw_clean); if (x->second->ptw_clean_t == NULL) { _MSG("Not enough free memory to copy PTW state", MSGFLAG_ERROR); return 0; } x->second->ptw_vague_t = PTW2_copyattackstate(x->second->ptw_vague); if (x->second->ptw_vague_t == NULL) { _MSG("Not enough free memory to copy PTW state", MSGFLAG_ERROR); PTW2_freeattackstate(x->second->ptw_clean_t); return 0; } x->second->last_crack_ivs = x->second->num_ptw_ivs_t = x->second->num_ptw_ivs; x->second->last_crack_vivs = x->second->num_ptw_vivs_t = x->second->num_ptw_vivs; x->second->threaded = 1; x->second->ptw_attempt = 1; _MSG("Trying to crack WEP key on " + x->second->bssid.Mac2String() + ": " + IntToString(x->second->num_ptw_vivs_t + x->second->num_ptw_ivs_t) + " IVs", MSGFLAG_INFO); // Only use trylock, this is bad but we should never get here if we've // got a running thread, but I don't want us to block if something gets funny pthread_mutex_trylock(&(x->second->crackdone)); pthread_create(&(x->second->crackthread), NULL, kisptw_crack, x->second); } } return 1; } int kisptw_datachain_hook(CHAINCALL_PARMS) { kisptw_state *kptw = (kisptw_state *) auxdata; kisptw_net *pnet = NULL; // Fetch the info from the packet chain data kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); // No 802.11 info, we don't handle it. if (packinfo == NULL) { return 0; } // Not an 802.11 frame type we known how to track, we'll just skip // it, too if (packinfo->corrupt || packinfo->type == packet_noise || packinfo->type == packet_unknown || packinfo->subtype == packet_sub_unknown) { return 0; } kis_data_packinfo *datainfo = (kis_data_packinfo *) in_pack->fetch(_PCM(PACK_COMP_BASICDATA)); // No data info? We can't handle it if (datainfo == NULL) { return 0; } // Make sure we got a network Netracker::tracked_network *net; kis_netracker_netinfo *netpackinfo = (kis_netracker_netinfo *) in_pack->fetch(_PCM(PACK_COMP_TRACKERNET)); // No network? Can't handle this either. if (netpackinfo == NULL) { return 0; } net = netpackinfo->netref; // Make sure we got a client, too Netracker::tracked_client *cli; kis_netracker_cliinfo *clipackinfo = (kis_netracker_cliinfo *) in_pack->fetch(_PCM(PACK_COMP_TRACKERCLIENT)); // No network? Can't handle this either. if (clipackinfo == NULL) { return 0; } cli = clipackinfo->cliref; kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } } // Handle WEP + PTW if (packinfo->cryptset == crypt_wep && chunk != NULL && packinfo->header_offset < chunk->length && chunk->length - packinfo->header_offset > 7) { if (chunk->data[packinfo->header_offset + 3] & 0x20) { return 0; } if (kptw->netmap.find(net->bssid) == kptw->netmap.end()) { pnet = new kisptw_net; pnet->ptw_clean = pnet->ptw_vague = NULL; pnet->ptw_clean_t = pnet->ptw_vague_t = NULL; pnet->num_ptw_ivs = pnet->num_ptw_vivs = 0; pnet->num_ptw_ivs_t = pnet->num_ptw_vivs_t = 0; pnet->last_crack_vivs = pnet->last_crack_ivs = 0; pnet->ptw_solved = 0; pnet->ptw_attempt = 0; pnet->threaded = 0; pnet->bssid = net->bssid; pnet->last_packet = time(0); memset(pnet->wepkey, 0, sizeof(pnet->wepkey)); pnet->len = 0; pthread_mutex_init(&(pnet->crackdone), NULL); kptw->netmap.insert(make_pair(net->bssid, pnet)); if (globalreg->netracker->GetNetworkTag(net->bssid, "WEP-AUTO") != "") { _MSG("Not collecting WEP PTW data on " + pnet->bssid.Mac2String() + " as it looks like an Auto-WEP network", MSGFLAG_INFO); pnet->ptw_solved = 1; } else { _MSG("Collecting WEP PTW data on " + pnet->bssid.Mac2String(), MSGFLAG_INFO); } } else { pnet = kptw->netmap.find(net->bssid)->second; } if (pnet->ptw_solved) return 1; int clearsize, i, j, k; int weight[16]; unsigned char clear[2048]; unsigned char clear2[2048]; memset(weight, 0, sizeof(weight)); memset(clear, 0, sizeof(clear)); memset(clear2, 0, sizeof(clear2)); k = known_clear(clear, &clearsize, clear2, chunk->data + packinfo->header_offset, chunk->length - packinfo->header_offset - 8); if (clearsize >= 16) { for (j = 0; j < k; j++) { for (i = 0; i < clearsize && 4 + i + packinfo->header_offset < chunk->length; i++) { clear[i+(PTW2_KSBYTES*j)] ^= chunk->data[4 + i + packinfo->header_offset]; } } if (pnet->ptw_clean == NULL) { pnet->ptw_clean = PTW2_newattackstate(); if (pnet->ptw_clean == NULL) { _MSG("Failed to allocate memory for PTW attack state", MSGFLAG_ERROR); return 1; } } if (pnet->ptw_vague == NULL) { pnet->ptw_vague = PTW2_newattackstate(); if (pnet->ptw_vague == NULL) { _MSG("Failed to allocate memory for PTW attack state", MSGFLAG_ERROR); return 1; } } int added = 0; if (k == 1) { if (PTW2_addsession(pnet->ptw_clean, chunk->data + packinfo->header_offset, clear, clear2, k)) { pnet->num_ptw_ivs++; added = 1; } } else { if (PTW2_addsession(pnet->ptw_vague, chunk->data + packinfo->header_offset, clear, clear2, k)) { pnet->num_ptw_vivs++; added = 1; } } if (added) { pnet->last_packet = time(0); globalreg->netracker->SetNetworkTag(pnet->bssid, "WEP-PTW-IV", IntToString(pnet->num_ptw_ivs), 0); globalreg->netracker->SetNetworkTag(pnet->bssid, "WEP-PTW-UNK", IntToString(pnet->num_ptw_vivs), 0); } } } return 0; } int kisptw_unregister(GlobalRegistry *in_globalreg) { int warned = 0; void *ret; if (state == NULL) return 0; globalreg->packetchain->RemoveHandler(&kisptw_datachain_hook, CHAINPOS_CLASSIFIER); globalreg->timetracker->RemoveTimer(state->timer_ref); // Cancel the thread and wait for it to shut down for (map::iterator x = state->netmap.begin(); x != state->netmap.end(); ++x) { if (x->second->threaded == 0) continue; warned++; pthread_cancel(x->second->crackthread); } if (warned) { _MSG("Aircrack-PTW: Canceling & waiting for " + IntToString(warned) + " pending PTW-crack threads to finish", MSGFLAG_INFO); for (map::iterator x = state->netmap.begin(); x != state->netmap.end(); ++x) { if (x->second->threaded == 0) continue; pthread_join(x->second->crackthread, &ret); } } return 0; } int kisptw_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; state = new kisptw_state; globalreg->packetchain->RegisterHandler(&kisptw_datachain_hook, state, CHAINPOS_CLASSIFIER, 100); state->timer_ref = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 5, NULL, 1, &kisptw_event_timer, state); state->alert_ref = globalreg->alertracker->RegisterAlert("WEPCRACK", sat_minute, 20, sat_second, 5); return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "AIRCRACK-PTW"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "Aircrack PTW Plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = kisptw_register; data->plugin_unregister = kisptw_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-ng.h0000664000175000017500000001604512124602454022267 0ustar dragorndragorn#ifndef _AIRCRACK_NG_H #define _AIRCRACK_NG_H #include #include #include #include "aircrack-ptw2-lib.h" #define SUCCESS 0 #define FAILURE 1 #define RESTART 2 #ifndef O_BINARY #define O_BINARY 0 #endif #define MAX_DICTS 128 #define ASCII_LOW_T 0x21 #define ASCII_HIGH_T 0x7E #define ASCII_VOTE_STRENGTH_T 150 #define ASCII_DISREGARD_STRENGTH 1 #define TEST_MIN_IVS 4 #define TEST_MAX_IVS 32 #define PTW_TRY_STEP 5000 #define SWAP(x,y) { unsigned char tmp = x; x = y; y = tmp; } #define KEYHSBYTES PTW2_KEYHSBYTES #define MAX_THREADS 128 #define CLOSE_IT 100000 #define GENPMKMAGIC 0x43575041 struct hashdb_head { uint32_t magic; uint8_t reserved1[3]; uint8_t ssidlen; uint8_t ssid[32]; }; struct hashdb_rec { uint8_t rec_size; char *word; uint8_t pmk[32]; } __attribute__ ((packed)); extern char * getVersion(char * progname, int maj, int min, int submin, int svnrev, int beta, int rc); extern int getmac(char * macAddress, int strict, unsigned char * mac); extern int readLine(char line[], int maxlength); extern int hexToInt(char s[], int len); extern int hexCharToInt(unsigned char c); #define S_LLC_SNAP "\xAA\xAA\x03\x00\x00\x00" #define S_LLC_SNAP_ARP (S_LLC_SNAP "\x08\x06") #define S_LLC_SNAP_IP (S_LLC_SNAP "\x08\x00") #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define KEYLIMIT 1000000 #define N_ATTACKS 17 enum KoreK_attacks { A_u15, /* semi-stable 15% */ A_s13, /* stable 13% */ A_u13_1, /* unstable 13% */ A_u13_2, /* unstable ? 13% */ A_u13_3, /* unstable ? 13% */ A_s5_1, /* standard 5% (~FMS) */ A_s5_2, /* other stable 5% */ A_s5_3, /* other stable 5% */ A_u5_1, /* unstable 5% no good ? */ A_u5_2, /* unstable 5% */ A_u5_3, /* unstable 5% no good */ A_u5_4, /* unstable 5% */ A_s3, /* stable 3% */ A_4_s13, /* stable 13% on q = 4 */ A_4_u5_1, /* unstable 5% on q = 4 */ A_4_u5_2, /* unstable 5% on q = 4 */ A_neg, /* helps reject false positives */ A_ptw, A_ptw_good, A_ptw_bad, A_first, A_second }; static struct options { int amode; /* attack mode */ int essid_set; /* essid set flag */ int bssid_set; /* bssid set flag */ char essid[33]; /* target ESSID */ unsigned char bssid[6]; /* target BSSID */ int nbcpu; /* # of cracker threads (= # of CPU) */ int is_quiet; /* quiet mode flag */ unsigned char debug[64]; /* user-defined WEP key */ int debug_row[64] ; /* user-defined Row WEP key */ unsigned char maddr[6]; /* MAC address filter */ int keylen; /* WEP key length */ int index; /* WEP key index */ float ffact; /* bruteforce factor */ int korek; /* attack strategy */ int is_fritz; /* use numeric keyspace */ int is_alnum; /* alphanum keyspace */ int is_bcdonly; /* binary coded decimal */ int do_brute; /* bruteforce last 2 KB */ int do_mt_brute; /* bruteforce last 2 KB multithreaded for SMP*/ int do_testy; /* experimental attack */ int do_ptw; /* PTW WEP attack */ char *dicts[MAX_DICTS]; /* dictionary files */ FILE *dict; /* dictionary file */ int nbdict; /* current dict number */ int no_stdin; /* if dict == stdin */ int hexdict[MAX_DICTS]; /* if dict in hex */ int showASCII; /* Show ASCII version of*/ /* the wepkey */ int l33t; /* no comment */ int stdin_dict; int probability; /* %of correct answers */ int votes[N_ATTACKS]; /* votes for korek attacks */ int brutebytes[64]; /* bytes to bruteforce */ int next_ptw_try; int max_ivs; char *bssidmerge; unsigned char *firstbssid; struct mergeBSSID * bssid_list_1st; struct AP_info *ap; int wep_decloak; int ptw_attack; int visual_inspection; /* Enabling/disabling visual */ /* inspection of the different */ /* keybytes */ int oneshot; /* Do PTW once */ char * logKeyToFile; } opt; typedef struct { int idx, val; } vote; struct WPA_hdsk { unsigned char stmac[6]; /* supplicant MAC */ unsigned char snonce[32]; /* supplicant nonce */ unsigned char anonce[32]; /* authenticator nonce */ unsigned char keymic[16]; /* eapol frame MIC */ unsigned char eapol[256]; /* eapol frame contents */ int eapol_size; /* eapol frame size */ int keyver; /* key version (TKIP / AES) */ int state; /* handshake completion */ }; struct AP_info { struct AP_info *next; /* next AP in linked list */ unsigned char bssid[6]; /* access point MAC address */ char essid[33]; /* access point identifier */ unsigned char lanip[4]; /* IP address if unencrypted */ unsigned char *ivbuf; /* table holding WEP IV data */ unsigned char **uiv_root; /* IV uniqueness root struct */ long ivbuf_size; /* IV buffer allocated size */ long nb_ivs; /* total number of unique IVs */ long nb_ivs_clean; /* total number of unique IVs */ long nb_ivs_vague; /* total number of unique IVs */ int crypt; /* encryption algorithm */ int eapol; /* set if EAPOL is present */ int target; /* flag set if AP is a target */ struct ST_info *st_1st; /* linked list of stations */ struct WPA_hdsk wpa; /* valid WPA handshake data */ PTW2_attackstate *ptw_clean; PTW2_attackstate *ptw_vague; }; struct ST_info { struct AP_info *ap; /* parent AP */ struct ST_info *next; /* next supplicant */ struct WPA_hdsk wpa; /* WPA handshake data */ unsigned char stmac[6]; /* client MAC address */ }; struct mergeBSSID { unsigned char bssid [6]; /* BSSID */ char unused[2]; /* Alignment */ int convert; /* Does this BSSID has to */ /* be converted */ struct mergeBSSID * next; }; struct WPA_data { struct AP_info* ap; /* AP information */ int thread; /* number of this thread */ int nkeys; /* buffer capacity */ char *key_buffer; /* queue as a circular buffer for feeding and consuming keys */ int front; /* front marker for the circular buffers */ int back; /* back marker for the circular buffers */ char key[128]; /* cracked key (0 while not found) */ pthread_cond_t cond; /* condition for waiting when buffer is full until keys are tried and new keys can be written */ pthread_mutex_t mutex; }; void show_wep_stats( int B, int force, PTW2_tableentry table[PTW2_KEYHSBYTES][PTW2_n], int choices[KEYHSBYTES], int depth[KEYHSBYTES], int prod ); #endif /* _AIRCRACK_NG_H */ kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-crypto.cc0000664000175000017500000011321512124602454023336 0ustar dragorndragorn/* * MD5, SHA-1, RC4 and AES implementations * * Copyright (C) 2001-2004 Christophe Devine * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "aircrack-crypto.h" #include "aircrack-crctable.h" #include "aircrack-ptw2-lib.h" #include "aircrack-ng.h" #define GET_UINT32_LE(n,b,i) \ { \ (n) = ( (uint32) (b)[(i) ] ) \ | ( (uint32) (b)[(i) + 1] << 8 ) \ | ( (uint32) (b)[(i) + 2] << 16 ) \ | ( (uint32) (b)[(i) + 3] << 24 ); \ } #define PUT_UINT32_LE(n,b,i) \ { \ (b)[(i) ] = (uint8) ( (n) ); \ (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \ (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \ (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \ } #define GET_UINT32_BE(n,b,i) \ { \ (n) = ( (uint32) (b)[(i) ] << 24 ) \ | ( (uint32) (b)[(i) + 1] << 16 ) \ | ( (uint32) (b)[(i) + 2] << 8 ) \ | ( (uint32) (b)[(i) + 3] ); \ } #define PUT_UINT32_BE(n,b,i) \ { \ (b)[(i) ] = (uint8) ( (n) >> 24 ); \ (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ (b)[(i) + 3] = (uint8) ( (n) ); \ } static uchar ZERO[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* RC4 encryption/ WEP decryption check */ /* SSL decryption */ int encrypt_wep( uchar *data, int len, uchar *key, int keylen ) { RC4_KEY S; RC4_set_key( &S, keylen, key ); RC4( &S, len, data, data ); return ( 0 ); } int decrypt_wep( uchar *data, int len, uchar *key, int keylen ) { encrypt_wep (data,len,key,keylen); return( check_crc_buf( data, len - 4 ) ); } /* An implementation of the ARC4 algorithm */ void rc4_setup( struct rc4_state *s, unsigned char *key, int length ) { int i, j, k, *m, a; s->x = 0; s->y = 0; m = s->m; for( i = 0; i < 256; i++ ) { m[i] = i; } j = k = 0; for(i=0 ; i < 256; i++ ) { a = m[i]; j = (unsigned char) ( j + a + key[k] ); m[i] = m[j]; m[j] = a; if( ++k >= length ) k = 0; } } void rc4_crypt( struct rc4_state *s, unsigned char *data, int length ) { int i, x, y, *m, a, b; x = s->x; y = s->y; m = s->m; for( i = 0; i < length; i++ ) { x = (unsigned char) ( x + 1 ); a = m[x]; y = (unsigned char) ( y + a ); m[x] = b = m[y]; m[y] = a; data[i] ^= m[(unsigned char) ( a + b )]; } s->x = x; s->y = y; } /* WEP (barebone RC4) en-/decryption routines */ /* int encrypt_wep( uchar *data, int len, uchar *key, int keylen ) { struct rc4_state S; rc4_setup( &S, key, keylen ); rc4_crypt( &S, data, len ); return( 0 ); } int decrypt_wep( uchar *data, int len, uchar *key, int keylen ) { struct rc4_state S; rc4_setup( &S, key, keylen ); rc4_crypt( &S, data, len ); return( check_crc_buf( data, len - 4 ) ); } */ /* derive the PMK from the passphrase and the essid */ void calc_pmk( char *key, char *essid_pre, uchar pmk[40] ) { int i, j, slen; uchar buffer[65]; char essid[33+4]; SHA_CTX ctx_ipad; SHA_CTX ctx_opad; SHA_CTX sha1_ctx; memset(essid, 0, sizeof(essid)); memcpy(essid, essid_pre, strlen(essid_pre)); slen = strlen( essid ) + 4; /* setup the inner and outer contexts */ memset( buffer, 0, sizeof( buffer ) ); strncpy( (char *) buffer, key, sizeof( buffer ) - 1 ); for( i = 0; i < 64; i++ ) buffer[i] ^= 0x36; SHA1_Init( &ctx_ipad ); SHA1_Update( &ctx_ipad, buffer, 64 ); for( i = 0; i < 64; i++ ) buffer[i] ^= 0x6A; SHA1_Init( &ctx_opad ); SHA1_Update( &ctx_opad, buffer, 64 ); /* iterate HMAC-SHA1 over itself 8192 times */ essid[slen - 1] = '\1'; HMAC(EVP_sha1(), (uchar *)key, strlen(key), (uchar*)essid, slen, pmk, NULL); memcpy( buffer, pmk, 20 ); for( i = 1; i < 4096; i++ ) { memcpy( &sha1_ctx, &ctx_ipad, sizeof( sha1_ctx ) ); SHA1_Update( &sha1_ctx, buffer, 20 ); SHA1_Final( buffer, &sha1_ctx ); memcpy( &sha1_ctx, &ctx_opad, sizeof( sha1_ctx ) ); SHA1_Update( &sha1_ctx, buffer, 20 ); SHA1_Final( buffer, &sha1_ctx ); for( j = 0; j < 20; j++ ) pmk[j] ^= buffer[j]; } essid[slen - 1] = '\2'; HMAC(EVP_sha1(), (uchar *)key, strlen(key), (uchar*)essid, slen, pmk+20, NULL); memcpy( buffer, pmk + 20, 20 ); for( i = 1; i < 4096; i++ ) { memcpy( &sha1_ctx, &ctx_ipad, sizeof( sha1_ctx ) ); SHA1_Update( &sha1_ctx, buffer, 20 ); SHA1_Final( buffer, &sha1_ctx ); memcpy( &sha1_ctx, &ctx_opad, sizeof( sha1_ctx ) ); SHA1_Update( &sha1_ctx, buffer, 20 ); SHA1_Final( buffer, &sha1_ctx ); for( j = 0; j < 20; j++ ) pmk[j + 20] ^= buffer[j]; } } // void calc_ptk (struct WPA_hdsk *wpa, unsigned char bssid[6], unsigned char pmk[32], unsigned char ptk[80]) { // int i; // uchar pke[100]; // HMAC_CTX ctx; // // memcpy( pke, "Pairwise key expansion", 23 ); // // if( memcmp( wpa->stmac, bssid, 6 ) < 0 ) // { // memcpy( pke + 23, wpa->stmac, 6 ); // memcpy( pke + 29, bssid, 6 ); // } // else // { // memcpy( pke + 23, bssid, 6 ); // memcpy( pke + 29, wpa->stmac, 6 ); // } // // if( memcmp( wpa->snonce, wpa->anonce, 32 ) < 0 ) // { // memcpy( pke + 35, wpa->snonce, 32 ); // memcpy( pke + 67, wpa->anonce, 32 ); // } // else // { // memcpy( pke + 35, wpa->anonce, 32 ); // memcpy( pke + 67, wpa->snonce, 32 ); // } // // HMAC_CTX_init(&ctx); // HMAC_Init_ex(&ctx, pmk, 32, EVP_sha1(), NULL); // for(i = 0; i < 4; i++ ) // { // pke[99] = i; // //HMAC(EVP_sha1(), values[0], 32, pke, 100, ptk + i * 20, NULL); // HMAC_Init_ex(&ctx, 0, 0, 0, 0); // HMAC_Update(&ctx, pke, 100); // HMAC_Final(&ctx, ptk + i*20, NULL); // } // HMAC_CTX_cleanup(&ctx); // } void calc_mic (struct AP_info *ap, unsigned char pmk[32], unsigned char ptk[80], unsigned char mic[20]) { int i; uchar pke[100]; HMAC_CTX ctx; memcpy( pke, "Pairwise key expansion", 23 ); if( memcmp( ap->wpa.stmac, ap->bssid, 6 ) < 0 ) { memcpy( pke + 23, ap->wpa.stmac, 6 ); memcpy( pke + 29, ap->bssid, 6 ); } else { memcpy( pke + 23, ap->bssid, 6 ); memcpy( pke + 29, ap->wpa.stmac, 6 ); } if( memcmp( ap->wpa.snonce, ap->wpa.anonce, 32 ) < 0 ) { memcpy( pke + 35, ap->wpa.snonce, 32 ); memcpy( pke + 67, ap->wpa.anonce, 32 ); } else { memcpy( pke + 35, ap->wpa.anonce, 32 ); memcpy( pke + 67, ap->wpa.snonce, 32 ); } HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, pmk, 32, EVP_sha1(), NULL); for(i = 0; i < 4; i++ ) { pke[99] = i; //HMAC(EVP_sha1(), values[0], 32, pke, 100, ptk + i * 20, NULL); HMAC_Init_ex(&ctx, 0, 0, 0, 0); HMAC_Update(&ctx, pke, 100); HMAC_Final(&ctx, ptk + i*20, NULL); } HMAC_CTX_cleanup(&ctx); if( ap->wpa.keyver == 1 ) { HMAC(EVP_md5(), ptk, 16, ap->wpa.eapol, ap->wpa.eapol_size, mic, NULL); } else { HMAC(EVP_sha1(), ptk, 16, ap->wpa.eapol, ap->wpa.eapol_size, mic, NULL); } } unsigned long calc_crc( unsigned char * buf, int len) { unsigned long crc = 0xFFFFFFFF; for( ; len > 0; len--, buf++ ) crc = crc_tbl[(crc ^ *buf) & 0xFF] ^ ( crc >> 8 ); return( ~crc ); } //without inversion, must be used for bit flipping attacks unsigned long calc_crc_plain( unsigned char * buf, int len) { unsigned long crc = 0x00000000; for( ; len > 0; len--, buf++ ) crc = crc_tbl[(crc ^ *buf) & 0xFF] ^ ( crc >> 8 ); return( crc ); } /* CRC checksum verification routine */ int check_crc_buf( unsigned char *buf, int len ) { unsigned long crc; crc = calc_crc(buf, len); buf+=len; return( ( ( crc ) & 0xFF ) == buf[0] && ( ( crc >> 8 ) & 0xFF ) == buf[1] && ( ( crc >> 16 ) & 0xFF ) == buf[2] && ( ( crc >> 24 ) & 0xFF ) == buf[3] ); } /* Add CRC32 */ int add_crc32(unsigned char* data, int length) { unsigned long crc; crc = calc_crc(data, length); data[length] = (crc ) & 0xFF; data[length+1] = (crc >> 8) & 0xFF; data[length+2] = (crc >> 16) & 0xFF; data[length+3] = (crc >> 24) & 0xFF; return 0; } int add_crc32_plain(unsigned char* data, int length) { unsigned long crc; crc = calc_crc_plain(data, length); data[length] = (crc ) & 0xFF; data[length+1] = (crc >> 8) & 0xFF; data[length+2] = (crc >> 16) & 0xFF; data[length+3] = (crc >> 24) & 0xFF; return 0; } int calc_crc_buf( unsigned char *buf, int len ) { return (calc_crc(buf, len)); } void *get_da(unsigned char *wh) { if (wh[1] & IEEE80211_FC1_DIR_FROMDS) return wh + 4; else return wh + 4 + 6*2; } void *get_sa(unsigned char *wh) { if (wh[1] & IEEE80211_FC1_DIR_FROMDS) return wh + 4 + 6*2; else return wh + 4 + 6; } int is_ipv6(uint8_t *wh) { if(memcmp(wh+4, "\x33\x33", 2) == 0 || memcmp(wh+16, "\x33\x33", 2) == 0) return 1; return 0; } int is_dhcp_discover(uint8_t *wh, int len) { if( (memcmp(wh+4, BROADCAST, 6) == 0 || memcmp(wh+16, BROADCAST, 6) == 0) && (len >= 360 - 24 - 4 - 4 && len <= 380 - 24 - 4 - 4 ) ) return 1; return 0; } int is_arp(void *wh, int len) { int arpsize = 8 + 8 + 10*2; if(wh) {} /* remove non BROADCAST frames? could be anything, but * chances are good that we got an arp response tho. */ if (len == arpsize || len == 54) return 1; return 0; } int is_spantree(uint8_t *wh) { if ( memcmp( wh + 4, SPANTREE, 6 ) == 0 || memcmp( wh + 16, SPANTREE, 6 ) == 0 ) return 1; return 0; } int is_cdp_vtp(uint8_t *wh) { if ( memcmp( wh + 4, CDP_VTP, 6 ) == 0 || memcmp( wh + 16, CDP_VTP, 6 ) == 0 ) return 1; return 0; } /* weight is used for guesswork in PTW. Can be null if known_clear is not for * PTW, but just for getting known clear-text. */ int known_clear(uint8_t *clear, int *clen, unsigned char *weight, unsigned char *wh, int len) { unsigned char *ptr = (unsigned char *) clear; int num; if(is_arp(wh, len)) /*arp*/ { len = sizeof(S_LLC_SNAP_ARP) - 1; memcpy(ptr, S_LLC_SNAP_ARP, len); ptr += len; /* arp hdr */ len = 6; memcpy(ptr, "\x00\x01\x08\x00\x06\x04", len); ptr += len; /* type of arp */ len = 2; if (memcmp(get_da(wh), "\xff\xff\xff\xff\xff\xff", 6) == 0) memcpy(ptr, "\x00\x01", len); else memcpy(ptr, "\x00\x02", len); ptr += len; /* src mac */ len = 6; memcpy(ptr, get_sa(wh), len); ptr += len; len = ptr - ((unsigned char*)clear); *clen = len; if (weight) memset(weight, 0xFF, len); return 1; } else if(is_spantree(wh)) /*spantree*/ { len = sizeof(S_LLC_SNAP_SPANTREE) - 1; memcpy(ptr, S_LLC_SNAP_SPANTREE, len); ptr += len; len = ptr - ((unsigned char*)clear); *clen = len; if (weight) memset(weight, 0xFF, len); return 1; } else if(is_cdp_vtp(wh)) /*spantree*/ { len = sizeof(S_LLC_SNAP_CDP) - 1; memcpy(ptr, S_LLC_SNAP_CDP, len); ptr += len; len = ptr - ((unsigned char*)clear); *clen = len; if (weight) memset(weight, 0xFF, len); return 1; } else /* IP */ { unsigned short iplen = htons(len - 8); // printf("Assuming IP %d\n", len); len = sizeof(S_LLC_SNAP_IP) - 1; memcpy(ptr, S_LLC_SNAP_IP, len); ptr += len; #if 1 //version=4; header_length=20; services=0 len = 2; memcpy(ptr, "\x45\x00", len); ptr += len; //ip total length memcpy(ptr, &iplen, len); ptr += len; /* no guesswork */ if (!weight) { *clen = ptr - ((unsigned char*)clear); return 1; } #if 1 /* setting IP ID 0 is ok, as we * bruteforce it later */ //ID=0 len=2; memcpy(ptr, "\x00\x00", len); ptr += len; //ip flags=don't fragment len=2; memcpy(ptr, "\x40\x00", len); ptr += len; #endif #endif len = ptr - ((unsigned char*)clear); *clen = len; //first possibility done memcpy(clear+PTW2_KSBYTES, clear, len); memcpy(clear+PTW2_KSBYTES+14, "\x00\x00", 2); //ip flags=none num=2; assert(weight); memset(weight, 0xFF, len); memset(weight+PTW2_KSBYTES, 0xFF, len); weight[12] = 0; weight[13] = 0; weight[12+PTW2_KSBYTES] = 0; weight[13+PTW2_KSBYTES] = 0; weight[14] = 220; weight[14+PTW2_KSBYTES] = 35; return num; } *clen=0; return 1; } /* derive the pairwise transcient keys from a bunch of stuff */ int calc_ptk( struct WPA_ST_info *wpa, uchar pmk[32] ) { int i; uchar pke[100]; uchar mic[20]; memcpy( pke, "Pairwise key expansion", 23 ); if( memcmp( wpa->stmac, wpa->bssid, 6 ) < 0 ) { memcpy( pke + 23, wpa->stmac, 6 ); memcpy( pke + 29, wpa->bssid, 6 ); } else { memcpy( pke + 23, wpa->bssid, 6 ); memcpy( pke + 29, wpa->stmac, 6 ); } if( memcmp( wpa->snonce, wpa->anonce, 32 ) < 0 ) { memcpy( pke + 35, wpa->snonce, 32 ); memcpy( pke + 67, wpa->anonce, 32 ); } else { memcpy( pke + 35, wpa->anonce, 32 ); memcpy( pke + 67, wpa->snonce, 32 ); } for( i = 0; i < 4; i++ ) { pke[99] = i; HMAC(EVP_sha1(), pmk, 32, pke, 100, wpa->ptk + i * 20, NULL ); } /* check the EAPOL frame MIC */ if( ( wpa->keyver & 0x07 ) == 1 ) HMAC(EVP_md5(), wpa->ptk, 16, wpa->eapol, wpa->eapol_size, mic, NULL ); else HMAC(EVP_sha1(), wpa->ptk, 16, wpa->eapol, wpa->eapol_size, mic, NULL ); return( memcmp( mic, wpa->keymic, 16 ) == 0 ); } int init_michael(struct Michael *mic, uchar key[8]) { mic->key0 = key[0]<<0 | key[1]<<8 | key[2]<<16 | key[3]<<24; mic->key1 = key[4]<<0 | key[5]<<8 | key[6]<<16 | key[7]<<24; // and reset the message mic->left = mic->key0; mic->right = mic->key1; mic->nBytesInM = 0; mic->message = 0; return 0; } int michael_append_byte(struct Michael *mic, uchar byte) { mic->message |= (byte << (8*mic->nBytesInM)); mic->nBytesInM++; // Process the word if it is full. if( mic->nBytesInM >= 4 ) { mic->left ^= mic->message; mic->right ^= ROL32( mic->left, 17 ); mic->left += mic->right; mic->right ^= ((mic->left & 0xff00ff00) >> 8) | ((mic->left & 0x00ff00ff) << 8); mic->left += mic->right; mic->right ^= ROL32( mic->left, 3 ); mic->left += mic->right; mic->right ^= ROR32( mic->left, 2 ); mic->left += mic->right; // Clear the buffer mic->message = 0; mic->nBytesInM = 0; } return 0; } int michael_remove_byte(struct Michael *mic, uchar bytes[4]) { if( mic->nBytesInM == 0 ) { // Clear the buffer mic->message = bytes[0] << 0 | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; mic->nBytesInM = 4; mic->left -= mic->right; mic->right ^= ROR32( mic->left, 2 ); mic->left -= mic->right; mic->right ^= ROL32( mic->left, 3 ); mic->left -= mic->right; mic->right ^= ((mic->left & 0xff00ff00) >> 8) | ((mic->left & 0x00ff00ff) << 8); mic->left -= mic->right; mic->right ^= ROL32( mic->left, 17 ); mic->left ^= mic->message; } mic->nBytesInM--; mic->message &= ~(0xFF << (8*mic->nBytesInM)); return 0; } int michael_append(struct Michael *mic, uchar *bytes, int length) { while(length > 0) { michael_append_byte(mic, *bytes++); length--; } return 0; } int michael_remove(struct Michael *mic, uchar *bytes, int length) { while(length >= 4) { michael_remove_byte(mic, (bytes+length-4)); length--; } return 0; } int michael_finalize(struct Michael *mic) { // Append the minimum padding michael_append_byte(mic, 0x5a ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); // and then zeroes until the length is a multiple of 4 while( mic->nBytesInM != 0 ) { michael_append_byte(mic, 0 ); } // The appendByte function has already computed the result. mic->mic[0] = (mic->left >> 0 ) & 0xff; mic->mic[1] = (mic->left >> 8 ) & 0xff; mic->mic[2] = (mic->left >> 16) & 0xff; mic->mic[3] = (mic->left >> 24) & 0xff; mic->mic[4] = (mic->right >> 0 ) & 0xff; mic->mic[5] = (mic->right >> 8 ) & 0xff; mic->mic[6] = (mic->right >> 16) & 0xff; mic->mic[7] = (mic->right >> 24) & 0xff; return 0; } int michael_finalize_zero(struct Michael *mic) { // Append the minimum padding michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); michael_append_byte(mic, 0 ); // and then zeroes until the length is a multiple of 4 while( mic->nBytesInM != 0 ) { michael_append_byte(mic, 0 ); } // The appendByte function has already computed the result. mic->mic[0] = (mic->left >> 0 ) & 0xff; mic->mic[1] = (mic->left >> 8 ) & 0xff; mic->mic[2] = (mic->left >> 16) & 0xff; mic->mic[3] = (mic->left >> 24) & 0xff; mic->mic[4] = (mic->right >> 0 ) & 0xff; mic->mic[5] = (mic->right >> 8 ) & 0xff; mic->mic[6] = (mic->right >> 16) & 0xff; mic->mic[7] = (mic->right >> 24) & 0xff; return 0; } int michael_test(uchar key[8], uchar *message, int length, uchar out[8]) { int i=0; struct Michael mic0; struct Michael mic1; struct Michael mic2; struct Michael mic; init_michael(&mic0, (unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00"); init_michael(&mic1, (unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00"); init_michael(&mic2, (unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00"); michael_append_byte(&mic0, 0x02); michael_append_byte(&mic1, 0x01); michael_append_byte(&mic2, 0x03); michael_finalize(&mic0); michael_finalize_zero(&mic1); michael_finalize(&mic2); printf("Blub 2:"); for(i=0; i<8; i++) { printf("%02X ", mic0.mic[i]); } printf("\n"); printf("Blub 1:"); for(i=0; i<8; i++) { printf("%02X ", mic1.mic[i]); } printf("\n"); printf("Blub 3:"); for(i=0; i<8; i++) { printf("%02X ", mic2.mic[i]); } printf("\n"); init_michael(&mic, key); michael_append(&mic, message, length); michael_finalize(&mic); return (memcmp(mic.mic, out, 8) == 0); } int calc_tkip_mic_key(uchar* packet, int length, uchar key[8]) { int z, koffset=0, is_qos=0; uchar smac[6], dmac[6], bssid[6]; uchar prio[4]; uchar message[4096]; uchar *ptr; struct Michael mic; bzero(message, 4096); z = ( ( packet[1] & 3 ) != 3 ) ? 24 : 30; if(length < z) return 0; /* Check if 802.11e (QoS) */ if( (packet[0] & 0x80) == 0x80) { z+=2; is_qos = 1; } bzero(prio, 4); if(is_qos) { prio[0] = packet[z-2] & 0x0f; } switch( packet[1] & 3 ) { case 0: memcpy( bssid, packet + 16, 6 ); memcpy( dmac, packet + 4, 6 ); memcpy( smac, packet + 10, 6 ); break; case 1: memcpy( bssid, packet + 4, 6 ); memcpy( dmac, packet + 16, 6 ); memcpy( smac, packet + 10, 6 ); koffset = 48+8; break; case 2: memcpy( bssid, packet + 10, 6 ); memcpy( dmac, packet + 4, 6 ); memcpy( smac, packet + 16, 6 ); koffset = 48; break; default: memcpy( bssid, packet + 10, 6 ); memcpy( dmac, packet + 16, 6 ); memcpy( smac, packet + 24, 6 ); break; } ptr = message; memcpy(ptr, dmac, 6); ptr+=6; memcpy(ptr, smac, 6); ptr+=6; memcpy(ptr, prio, 4); ptr+=4; memcpy(ptr, packet+z, length-z-8); ptr+=length-z-8; memcpy(ptr, "\x5a", 1); ptr+=1; memcpy(ptr, ZERO, 4); ptr+=4; if((ptr-message) % 4 > 0) memcpy(ptr, ZERO, 4-((ptr-message)%4)); ptr+=4-((ptr-message)%4); init_michael(&mic, packet+length-8); michael_remove(&mic, message, (ptr-message)); mic.mic[0] = (mic.left >> 0 ) & 0xFF; mic.mic[1] = (mic.left >> 8 ) & 0xFF; mic.mic[2] = (mic.left >> 16) & 0xFF; mic.mic[3] = (mic.left >> 24) & 0xFF; mic.mic[4] = (mic.right >> 0 ) & 0xFF; mic.mic[5] = (mic.right >> 8 ) & 0xFF; mic.mic[6] = (mic.right >> 16) & 0xFF; mic.mic[7] = (mic.right >> 24) & 0xFF; memcpy(key, mic.mic, 8); return 0; } int calc_tkip_mic(uchar* packet, int length, uchar ptk[80], uchar value[8]) { int z, koffset=0, is_qos=0; uchar smac[6], dmac[6], bssid[6]; uchar prio[4]; struct Michael mic; z = ( ( packet[1] & 3 ) != 3 ) ? 24 : 30; if(length < z) return 0; /* Check if 802.11e (QoS) */ if( (packet[0] & 0x80) == 0x80) { z+=2; is_qos = 1; } switch( packet[1] & 3 ) { case 0: memcpy( bssid, packet + 16, 6 ); memcpy( dmac, packet + 4, 6 ); memcpy( smac, packet + 10, 6 ); break; case 1: memcpy( bssid, packet + 4, 6 ); memcpy( dmac, packet + 16, 6 ); memcpy( smac, packet + 10, 6 ); koffset = 48+8; break; case 2: memcpy( bssid, packet + 10, 6 ); memcpy( dmac, packet + 4, 6 ); memcpy( smac, packet + 16, 6 ); koffset = 48; break; default: memcpy( bssid, packet + 10, 6 ); memcpy( dmac, packet + 16, 6 ); memcpy( smac, packet + 24, 6 ); break; } if(koffset != 48 && koffset != 48+8) return 1; init_michael(&mic, ptk+koffset); michael_append(&mic, dmac, 6); michael_append(&mic, smac, 6); bzero(prio, 4); if(is_qos) { prio[0] = packet[z-2] & 0x0f; } michael_append(&mic, prio, 4); michael_append(&mic, packet+z, length - z); michael_finalize(&mic); memcpy(value, mic.mic, 8); return 0; } const int TkipSbox[2][256]= { { 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A }, { 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C } }; /* TKIP (RC4 + key mixing) decryption routine */ #define ROTR1(x) ((((x) >> 1) & 0x7FFF) ^ (((x) & 1) << 15)) #define LO8(x) ( (x) & 0x00FF ) #define LO16(x) ( (x) & 0xFFFF ) #define HI8(x) ( ((x) >> 8) & 0x00FF ) #define HI16(x) ( ((x) >> 16) & 0xFFFF ) #define MK16(hi,lo) ( (lo) ^ ( LO8(hi) << 8 ) ) #define TK16(N) MK16(TK1[2*(N)+1],TK1[2*(N)]) #define _S_(x) (TkipSbox[0][LO8(x)] ^ TkipSbox[1][HI8(x)]) int calc_tkip_ppk( uchar *h80211, int caplen, uchar TK1[16], uchar key[16] ) { int i, z; uint32_t IV32; uint16_t IV16; uint16_t PPK[6]; if(caplen) {} z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30; if ( GET_SUBTYPE(h80211[0]) == IEEE80211_FC0_SUBTYPE_QOS ) { z += 2; } IV16 = MK16( h80211[z], h80211[z + 2] ); IV32 = ( h80211[z + 4] ) | ( h80211[z + 5] << 8 ) | ( h80211[z + 6] << 16 ) | ( h80211[z + 7] << 24 ); PPK[0] = LO16( IV32 ); PPK[1] = HI16( IV32 ); PPK[2] = MK16( h80211[11], h80211[10] ); PPK[3] = MK16( h80211[13], h80211[12] ); PPK[4] = MK16( h80211[15], h80211[14] ); for( i = 0; i < 8; i++ ) { PPK[0] += _S_( PPK[4] ^ TK16( (i & 1) + 0 ) ); PPK[1] += _S_( PPK[0] ^ TK16( (i & 1) + 2 ) ); PPK[2] += _S_( PPK[1] ^ TK16( (i & 1) + 4 ) ); PPK[3] += _S_( PPK[2] ^ TK16( (i & 1) + 6 ) ); PPK[4] += _S_( PPK[3] ^ TK16( (i & 1) + 0 ) ) + i; } PPK[5] = PPK[4] + IV16; PPK[0] += _S_( PPK[5] ^ TK16(0) ); PPK[1] += _S_( PPK[0] ^ TK16(1) ); PPK[2] += _S_( PPK[1] ^ TK16(2) ); PPK[3] += _S_( PPK[2] ^ TK16(3) ); PPK[4] += _S_( PPK[3] ^ TK16(4) ); PPK[5] += _S_( PPK[4] ^ TK16(5) ); PPK[0] += ROTR1( PPK[5] ^ TK16(6) ); PPK[1] += ROTR1( PPK[0] ^ TK16(7) ); PPK[2] += ROTR1( PPK[1] ); PPK[3] += ROTR1( PPK[2] ); PPK[4] += ROTR1( PPK[3] ); PPK[5] += ROTR1( PPK[4] ); key[0] = HI8( IV16 ); key[1] = ( HI8( IV16 ) | 0x20 ) & 0x7F; key[2] = LO8( IV16 ); key[3] = LO8( (PPK[5] ^ TK16(0) ) >> 1); for( i = 0; i < 6; i++ ) { key[4 + ( 2 * i)] = LO8( PPK[i] ); key[5 + ( 2 * i)] = HI8( PPK[i] ); } return 0; } int decrypt_tkip( uchar *h80211, int caplen, uchar TK1[16] ) { uchar K[16]; int z; z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30; if ( GET_SUBTYPE(h80211[0]) == IEEE80211_FC0_SUBTYPE_QOS ) { z += 2; } calc_tkip_ppk( h80211, caplen, TK1, K ); return( decrypt_wep( h80211 + z + 8, caplen - z - 8, K, 16 ) ); } /* CCMP (AES-CTR-MAC) decryption routine */ static inline void XOR( uchar *dst, uchar *src, int len ) { int i; for( i = 0; i < len; i++ ) dst[i] ^= src[i]; } int decrypt_ccmp( uchar *h80211, int caplen, uchar TK1[16] ) { int is_a4, i, n, z, blocks; int data_len, last, offset; uchar B0[16], B[16], MIC[16]; uchar PN[6], AAD[32]; AES_KEY aes_ctx; is_a4 = ( h80211[1] & 3 ) == 3; z = 24 + 6 * is_a4; PN[0] = h80211[z + 7]; PN[1] = h80211[z + 6]; PN[2] = h80211[z + 5]; PN[3] = h80211[z + 4]; PN[4] = h80211[z + 1]; PN[5] = h80211[z + 0]; data_len = caplen - z - 8 - 8; B0[0] = 0x59; B0[1] = 0; memcpy( B0 + 2, h80211 + 10, 6 ); memcpy( B0 + 8, PN, 6 ); B0[14] = ( data_len >> 8 ) & 0xFF; B0[15] = ( data_len & 0xFF ); memset( AAD, 0, sizeof( AAD ) ); AAD[1] = 22 + 6 * is_a4; AAD[2] = h80211[0] & 0x8F; AAD[3] = h80211[1] & 0xC7; memcpy( AAD + 4, h80211 + 4, 3 * 6 ); AAD[22] = h80211[22] & 0x0F; if( is_a4 ) memcpy( AAD + 24, h80211 + 24, 6 ); AES_set_encrypt_key( TK1, 128, &aes_ctx ); AES_encrypt( B0, MIC, &aes_ctx ); XOR( MIC, AAD, 16 ); AES_encrypt( MIC, MIC, &aes_ctx ); XOR( MIC, AAD + 16, 16 ); AES_encrypt( MIC, MIC, &aes_ctx ); B0[0] &= 0x07; B0[14] = B0[15] = 0; AES_encrypt( B0, B, &aes_ctx ); XOR( h80211 + caplen - 8, B, 8 ); blocks = ( data_len + 16 - 1 ) / 16; last = data_len % 16; offset = z + 8; for( i = 1; i <= blocks; i++ ) { n = ( last > 0 && i == blocks ) ? last : 16; B0[14] = ( i >> 8 ) & 0xFF; B0[15] = i & 0xFF; AES_encrypt( B0, B, &aes_ctx ); XOR( h80211 + offset, B, n ); XOR( MIC, h80211 + offset, n ); AES_encrypt( MIC, MIC, &aes_ctx ); offset += n; } return( memcmp( h80211 + offset, MIC, 8 ) == 0 ); } /* ********************************************************************** * Routine: Phase 1 -- generate P1K, given TA, TK, IV32 * * Inputs: * TK[] = Temporal Key [128 bits] * TA[] = transmitter's MAC address [ 48 bits] * IV32 = upper 32 bits of IV [ 32 bits] * Output: * P1K[] = Phase 1 key [ 80 bits] * * Note: * This function only needs to be called every 2**16 frames, * although in theory it could be called every frame. * ********************************************************************** */ // void Phase1(u16b *P1K,const byte *TK,const byte *TA,u32b IV32) // { // int i; // /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ // P1K[0] = Lo16(IV32); // P1K[1] = Hi16(IV32); // P1K[2] = Mk16(TA[1],TA[0]); /* use TA[] as little-endian */ // P1K[3] = Mk16(TA[3],TA[2]); // P1K[4] = Mk16(TA[5],TA[4]); // /* Now compute an unbalanced Feistel cipher with 80-bit block */ // /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ // for (i=0; i < PHASE1_LOOP_CNT ;i++) // { /* Each add operation here is mod 2**16 */ // P1K[0] += _S_(P1K[4] ^ TK16((i&1)+0)); // P1K[1] += _S_(P1K[0] ^ TK16((i&1)+2)); // P1K[2] += _S_(P1K[1] ^ TK16((i&1)+4)); // P1K[3] += _S_(P1K[2] ^ TK16((i&1)+6)); // P1K[4] += _S_(P1K[3] ^ TK16((i&1)+0)); // P1K[4] += i; /* avoid "slide attacks" */ // } // } /* ********************************************************************** * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 * * Inputs: * TK[] = Temporal Key [128 bits] * P1K[] = Phase 1 output key [ 80 bits] * IV16 = low 16 bits of IV counter [ 16 bits] * Output: * RC4KEY[] = the key used to encrypt the frame [128 bits] * * Note: * The value {TA,IV32,IV16} for Phase1/Phase2 must be unique * across all frames using the same key TK value. Then, for a * given value of TK[], this TKIP48 construction guarantees that * the final RC4KEY value is unique across all frames. * * Suggested implementation optimization: if PPK[] is "overlaid" * appropriately on RC4KEY[], there is no need for the final * for loop below that copies the PPK[] result into RC4KEY[]. * ********************************************************************** */ // void Phase2(byte *RC4KEY,const byte *TK,const u16b *P1K,u16b IV16) // { // int i; // u16b PPK[6]; /* temporary key for mixing */ // /* all adds in the PPK[] equations below are mod 2**16 */ // for (i=0;i<5;i++) PPK[i]=P1K[i]; /* first, copy P1K to PPK */ // PPK[5] = P1K[4] + IV16; /* next, add in IV16 */ // /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ // PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ // PPK[1] += _S_(PPK[0] ^ TK16(1)); // PPK[2] += _S_(PPK[1] ^ TK16(2)); // PPK[3] += _S_(PPK[2] ^ TK16(3)); // PPK[4] += _S_(PPK[3] ^ TK16(4)); // PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ // /* Final sweep: bijective, linear. Rotates kill LSB correlations */ // PPK[0] += RotR1(PPK[5] ^ TK16(6)); // PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ // PPK[2] += RotR1(PPK[1]); // PPK[3] += RotR1(PPK[2]); // PPK[4] += RotR1(PPK[3]); // PPK[5] += RotR1(PPK[4]); // /* At this point, for a given key TK[0..15], the 96-bit output */ // /* value PPK[0..5] is guaranteed to be unique, as a function */ // /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ // /* is now a keyed permutation of {TA,IV32,IV16}. */ // /* Set RC4KEY[0..3], which includes cleartext portion of RC4 key */ // RC4KEY[0] = Hi8(IV16); /* RC4KEY[0..2] is the WEP IV */ // RC4KEY[1] =(Hi8(IV16) | 0x20) & 0x7F; /* Help avoid FMS weak keys */ // RC4KEY[2] = Lo8(IV16); // RC4KEY[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); // /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ // for (i=0;i<6;i++) // { // RC4KEY[4+2*i] = Lo8(PPK[i]); // RC4KEY[5+2*i] = Hi8(PPK[i]); // } // } kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-ptw2-lib.cc0000664000175000017500000007237512124602454023471 0ustar dragorndragorn/* * Copyright (c) 2007, 2008, Erik Tews, Andrei Pychkine and Ralf-Philipp Weinmann. * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. * If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. * If you * do not wish to do so, delete this exception statement from your * version. * If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include #include "pcap.h" #include "aircrack-ptw2-lib.h" #include "aircrack-ng.h" #define n PTW2_n #define CONTROLSESSIONS PTW2_CONTROLSESSIONS #define KSBYTES PTW2_KSBYTES #define IVBYTES PTW2_IVBYTES #define TESTBYTES 6 // Internal state of rc4 typedef struct { uint8_t i; uint8_t j; uint8_t s[n]; } rc4state; // Helper structures for sorting typedef struct { int keybyte; uint8_t value; int distance; } sorthelper; typedef struct { int keybyte; double difference; } doublesorthelper; // The rc4 initial state, the idendity permutation static const uint8_t rc4initial[] = {0,1,2,3,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18,19,20, 21,22,23,24,25,26,27,28,29,30, 31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50, 51,52,53,54,55,56,57,58,59,60, 61,62,63,64,65,66,67,68,69,70, 71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90, 91,92,93,94,95,96,97,98,99,100, 101,102,103,104,105,106,107,108,109,110, 111,112,113,114,115,116,117,118,119,120, 121,122,123,124,125,126,127,128,129,130, 131,132,133,134,135,136,137,138,139,140, 141,142,143,144,145,146,147,148,149,150, 151,152,153,154,155,156,157,158,159,160, 161,162,163,164,165,166,167,168,169,170, 171,172,173,174,175,176,177,178,179,180, 181,182,183,184,185,186,187,188,189,190, 191,192,193,194,195,196,197,198,199,200, 201,202,203,204,205,206,207,208,209,210, 211,212,213,214,215,216,217,218,219,220, 221,222,223,224,225,226,227,228,229,230, 231,232,233,234,235,236,237,238,239,240, 241,242,243,244,245,246,247,248,249,250, 251,252,253,254,255}; static const int coeffs[] = {300, 260, 240, 240, 240, 100, 50, 50, 30, 160, 30, 40, 30, 130, 40, 40, -120, 0, 16, 0, 100, 45}; /* static const int coeffs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 100, 45}; */ // Values for p_correct_i static const double eval[] = { 0.00534392069257663, 0.00531787585068872, 0.00531345769225911, 0.00528812219217898, 0.00525997750378221, 0.00522647312237696, 0.00519132541143668, 0.0051477139367225, 0.00510438884847959, 0.00505484662057323, 0.00500502783556246, 0.00495094196451801, 0.0048983441590402}; int tried, max_tries; int depth[KEYHSBYTES]; PTW2_tableentry keytable[KEYHSBYTES][n]; // For sorting static int compare(const void * ina, const void * inb) { PTW2_tableentry * a = (PTW2_tableentry * )ina; PTW2_tableentry * b = (PTW2_tableentry * )inb; if (a->votes > b->votes) { return -1; } else if (a->votes == b->votes) { return 0; } else { return 1; } } // For sorting /* static int comparedoublesorthelper(const void * ina, const void * inb) { doublesorthelper * a = (doublesorthelper * )ina; doublesorthelper * b = (doublesorthelper * )inb; if (a->difference > b->difference) { return 1; } else if (a->difference == b->difference) { return 0; } else { return -1; } } */ // RC4 key setup static void rc4init ( uint8_t * key, int keylen, rc4state * state) { int i; unsigned char j; uint8_t tmp; memcpy(state->s, &rc4initial, n); j = 0; for (i = 0; i < n; i++) { /* this should be: j = (j + state->s[i] + key[i % keylen]) % n; but as "j" is declared as unsigned char and n equals 256, we can "optimize" it */ j = (j + state->s[i] + key[i % keylen]); tmp = state->s[i]; state->s[i] = state->s[j]; state->s[j] = tmp; } state->i = 0; state->j = 0; } // RC4 key stream generation static uint8_t rc4update(rc4state * state) { uint8_t tmp; uint8_t k; state->i++; state->j += state->s[state->i]; tmp = state->s[state->i]; state->s[state->i] = state->s[state->j]; state->s[state->j] = tmp; k = state->s[state->i] + state->s[state->j]; return state->s[k]; } // For sorting static int comparesorthelper(const void * ina, const void * inb) { sorthelper * a = (sorthelper * ) ina; sorthelper * b = (sorthelper * ) inb; if (a->distance > b->distance) { return 1; } else if (a->distance == b->distance) { return 0; } else { return -1; } } /* * Guess the values for sigma_i * ivlen - how long was the iv (is used differently in original klein attack) * iv - IV which was used for this packet * keystream - keystream recovered * result - buffer for the values of sigma_i * kb - how many keybytes should be guessed */ static void guesskeybytes(int ivlen, uint8_t * iv, uint8_t * keystream, uint8_t * result, int kb) { uint8_t state[n]; uint8_t j = 0; uint8_t tmp; int i; int jj = ivlen; uint8_t ii; uint8_t s = 0; memcpy(state, rc4initial, n); for (i = 0; i < ivlen; i++) { j += state[i] + iv[i]; tmp = state[i]; state[i] = state[j]; state[j] = tmp; } for (i = 0; i < kb; i++) { tmp = jj - keystream[jj-1]; ii = 0; while(tmp != state[ii]) { ii++; } s += state[jj]; ii -= (j+s); result[i] = ii; jj++; } return; } /* * Is a guessed key correct? */ static int correct(PTW2_attackstate * state, uint8_t * key, int keylen) { int i; int j; int k; uint8_t keybuf[PTW2_KSBYTES]; rc4state rc4state; // We need at least 3 sessions to be somehow certain if (state->sessions_collected < 3) { return 0; } tried++; k = rand()%(state->sessions_collected-10); for ( i=k; i < k+10; i++) { memcpy(&keybuf[IVBYTES], key, keylen); memcpy(keybuf, state->sessions[i].iv, IVBYTES); rc4init(keybuf, keylen+IVBYTES, &rc4state); for (j = 0; j < TESTBYTES; j++) { if ((rc4update(&rc4state) ^ state->sessions[i].keystream[j]) != 0) { return 0; } } } return 1; } /* * Calculate the squaresum of the errors for both distributions */ /* static void getdrv(PTW2_tableentry orgtable[][n], int keylen, double * normal, double * ausreiser) { int i,j; int numvotes = 0; double e; double e2; double emax; double help = 0.0; double maxhelp = 0; double maxi = 0; for (i = 0; i < n; i++) { numvotes += orgtable[0][i].votes; } e = numvotes/n; for (i = 0; i < keylen; i++) { emax = eval[i] * numvotes; e2 = ((1.0 - eval[i])/255.0) * numvotes; normal[i] = 0; ausreiser[i] = 0; maxhelp = 0; maxi = 0; for (j = 0; j < n; j++) { if (orgtable[i][j].votes > maxhelp) { maxhelp = orgtable[i][j].votes; maxi = j; } } for (j = 0; j < n; j++) { if (j == maxi) { help = (1.0-orgtable[i][j].votes/emax); } else { help = (1.0-orgtable[i][j].votes/e2); } help = help*help; ausreiser[i] += help; help = (1.0-orgtable[i][j].votes/e); help = help*help; normal[i] += help; } } } */ /* * Guess a single keybyte */ static int doRound(PTW2_tableentry sortedtable[][n], int keybyte, int fixat, uint8_t fixvalue, int * searchborders, uint8_t * key, int keylen, PTW2_attackstate * state, uint8_t sum, int * strongbytes, int * bf, int validchars[][n]) { int i; uint8_t tmp; if (keybyte > 0) { if (!validchars[keybyte-1][key[keybyte-1]]) { return 0; } } if (keybyte == keylen) { return correct(state, key, keylen); } else if (bf[keybyte] == 1) { for (i = 0; i < n; i++) { key[keybyte] = i; if (doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, sum+i%n, strongbytes, bf, validchars)) { return 1; } } return 0; } else if (keybyte == fixat) { key[keybyte] = fixvalue-sum; return doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, fixvalue, strongbytes, bf, validchars); } else if (strongbytes[keybyte] == 1) { // printf("assuming byte %d to be strong\n", keybyte); tmp = 3 + keybyte; for (i = keybyte-1; i >= 1; i--) { tmp += 3 + key[i] + i; key[keybyte] = n-tmp; if(doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, (n-tmp+sum)%n, strongbytes, bf, validchars) == 1) { printf("hit with strongbyte for keybyte %d\n", keybyte); return 1; } } return 0; } else { for (i = 0; i < searchborders[keybyte]; i++) { key[keybyte] = sortedtable[keybyte][i].b - sum; if(!opt.is_quiet) { depth[keybyte] = i; keytable[keybyte][i].b = key[keybyte]; } if (doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, sortedtable[keybyte][i].b, strongbytes, bf, validchars)) { return 1; } } return 0; } } /* * Do the actual computation of the key */ static int doComputation(PTW2_attackstate * state, uint8_t * key, int keylen, PTW2_tableentry table[][n], sorthelper * sh2, int * strongbytes, int keylimit, int * bf, int validchars[][n]) { int i,j; int choices[KEYHSBYTES]; int prod; int fixat; int fixvalue; if(!opt.is_quiet) memcpy(keytable, table, sizeof(PTW2_tableentry) * n * keylen); for (i = 0; i < keylen; i++) { if (strongbytes[i] == 1) { choices[i] = i; } else { choices[i] = 1; } } i = 0; prod = 0; fixat = -1; fixvalue = 0; max_tries = keylimit; while(prod < keylimit) { if (doRound(table, 0, fixat, fixvalue, choices, key, keylen, state, 0, strongbytes, bf, validchars) == 1) { // printf("hit with %d choices\n", prod); return 1; } while( (i < (keylen-1) * (n-1)) && ((strongbytes[sh2[i].keybyte] == 1) || (bf[sh2[i].keybyte] == 1) ) ) { i++; } if(i >= ((keylen-1) * (n-1))) { break; } choices[sh2[i].keybyte]++; fixat = sh2[i].keybyte; // printf("choices[%d] is now %d\n", sh2[i].keybyte, choices[sh2[i].keybyte]); fixvalue = sh2[i].value; prod = 1; for (j = 0; j < keylen; j++) { prod *= choices[j]; if (bf[j] == 1) { prod *= n; } } // printf("prod is now %d\n", prod); /* do { i++; } while (strongbytes[sh2[i].keybyte] == 1); */ i++; } return 0; } static void doVote(PTW2_tableentry first[][n], PTW2_tableentry second[][n], int i, int attack, int value, uint8_t * iv, int weight, int keylength) { int q = PTW2_IVBYTES; int j; // printf("voting keybyte %d with attack %d to value %d\n", i, attack, value); // weight = 1; if (i < keylength) { first[i][value].votes += coeffs[attack]*weight; } else if(i < q+keylength) { for (j = 0; j <= i-keylength; j++) { value = (value + 256 - iv[j])&0xff; } // printf("doing iv vote\n"); first[keylength-1][value].votes += coeffs[attack]*weight; } else { for (j = 0; j < q; j++) { value = (value + 256 - iv[j])&0xff; } second[i - (q+keylength)][value].votes += coeffs[attack]*weight; } } #if 0 static void dumpTable(PTW2_tableentry * table, int i) { FILE * f; int j; f = fopen("tables.txt", "a"); if (f != NULL) { fprintf(f, "table %d\n", i); for (j = 0; j < n; j++) { fprintf(f, "byte %d with %d votes\n", table[j].b, table[j].votes); } fprintf(f, "\n"); } fclose(f); } #endif static void genVotes(PTW2_tableentry first[][n], PTW2_tableentry second[][n], uint8_t * iv, uint8_t * ks, int * weights, int keylength) { int i; int j; int temp; int dq; int Kq; int jq; int j2; int t2; int q = PTW2_IVBYTES; int S[n]; int Si[n]; int jj[n]; int numVotes = 2*keylength+q; // printf("doing vote iv[0] = %d, iv[1] = %d, iv[2] = %d, ks[0] = %d, ks[1] = %d, keylen = %d\n", iv[0], iv[1], iv[2], ks[0], ks[1], keylength); // int numVotes = keylength; for (i = 0; i < n; i++) { S[i] = i; } j = 0; for (i = 0; i < q; i++) { j = (j + S[i] + iv[i])&0xff; jj[i] = j; temp = S[i]; S[i] = S[j]; S[j] = temp; } for (i = 0; i < 256; i++) { Si[S[i]] = i; } dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i])&0xff; temp = Si[(i+q-ks[i+q-1]+256)&0xff]; Kq = (temp-dq+256)&0xff; int was_bad = 0; int i2; for (i2 = q; i2 < q+i; i2++) { if (S[i2] == temp) { doVote(first, second, i,A_ptw_bad, Kq, iv, weights[i+q-1], keylength); // votes[i][A_ptw_bad][Kq]++; was_bad = 1; break; } } if (!was_bad) { doVote(first, second, i, A_ptw_good, Kq, iv, weights[i+q-1], keylength); // votes[i][A_ptw_good][Kq]++; } doVote(first, second, i, A_ptw, Kq, iv, weights[i+q-1], keylength); // votes[i][A_ptw][Kq]++; } if (S[2] == 0) { if ((S[1] == 2) && (ks[0] == 2)) { dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i])&0xff; Kq = (1-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; Kq = (2-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; } } else if (ks[1] == 0) { dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i])&0xff; Kq = (2 - dq + 256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[1], keylength); // votes[i][A_neg][Kq]++; } } } else { dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i])&0xff; if ((ks[1] == 0) && (S[q+i] == 0)) { Kq = (2-dq+256)&0xff; doVote(first, second, i, A_u15, Kq, iv, weights[1], keylength); // votes[i][A_u15][Kq]++; } } } if ((S[1] == 1) && (ks[0] == S[2])) { dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i]) &0xff; Kq = (1-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; Kq = (2-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; } } if ((S[1] == 0) && (S[0] == 1) && (ks[0] == 1)) { dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i]) &0xff; Kq = (0-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; Kq = (1-dq+256)&0xff; doVote(first, second, i, A_neg, Kq, iv, weights[0], keylength); // votes[i][A_neg][Kq]++; } } dq = j; for (i = 0; i < numVotes; i++) { dq = (dq + S[q+i]) &0xff; if (S[1] == i+q) { if (ks[0] == q+i) { Kq = (Si[0] - dq + 256)&0xff; doVote(first, second, i, A_s13, Kq, iv, weights[0], keylength); // votes[i][A_s13][Kq]++; } else if (((1 - (q+i) - ks[0] + 512)&0xff) == 0) { Kq = (Si[ks[0]] - dq + 256)&0xff; doVote(first, second, i, A_u13_1, Kq, iv, weights[0], keylength); // votes[i][A_u13_1][Kq]++; } else if (Si[ks[0]] < q+i) { jq = Si[(Si[ks[0]] - (q+i)+512)&0xff]; if (jq != 1) { Kq = (jq - dq+256)&0xff; doVote(first, second, i, A_u5_1, Kq, iv, weights[0], keylength); // votes[i][A_u5_1][Kq]++; } } } if ((Si[ks[0]] == 2) && (S[q+i] == 1)) { Kq = (1-dq + 256)&0xff; doVote(first, second, i, A_u5_2, Kq, iv, weights[0], keylength); // votes[i][A_u5_2][Kq]++; } if (S[q+i] == q+i) { if ((S[1] == 0) && (ks[0] == q+i)) { Kq = (1-dq+256)&0xff; doVote(first, second, i, A_u13_2, Kq, iv, weights[0], keylength); // votes[i][A_u13_2][Kq]++; } else if ((((1-(q+i)-S[1]+512)&0xff)==0) && (ks[0] == S[1])) { Kq = (1-dq+256)&0xff; doVote(first, second, i, A_u13_3, Kq, iv, weights[0], keylength); // votes[i][A_u13_3][Kq]++; } else if (S[1] >= (((512-(q+i))&0xff)) && ((((q+i)+S[1]-Si[ks[0]]+256)&0xff)== 0)) { Kq = (1-dq+256)&0xff; doVote(first, second, i, A_u5_3, Kq, iv, weights[0], keylength); // votes[i][A_u5_3][Kq]++; } } if ( (S[1] < (q)) && (((S[1]+S[S[1]] - (q+i) + 256)&0xff) == 0) && (Si[ks[0]] != 1) && (Si[ks[0]] != S[S[1]])) { Kq = (Si[ks[0]]-dq+256)&0xff; doVote(first, second, i, A_s5_1, Kq, iv, weights[0], keylength); // votes[i][A_s5_1][Kq]++; } // if ( // (S[1] > (q+i)) && // (((S[2] + S[1] - (q+i) + 256) & 0xff) == 0) && // (Si[ks[0]] != 1) && // (Si[ks[0]] != S[S[1]]) // ) { // Kq = (Si[ks[0]] - dq + 256)&0xff; // votes[i][A_s5_1][Kq]++; // } if ((S[1] > (q+i)) && (((S[2] + S[1] - (q+i) + 256)&0xff) == 0) ) { if (ks[1] == S[1]) { jq = Si[(S[1] - S[2] + 256)&0xff]; if ((jq != 1) && (jq != 2)) { Kq = (jq - dq + 256)&0xff; doVote(first, second, i, A_s5_2, Kq, iv, weights[1], keylength); // votes[i][A_s5_2][Kq]++; } } else if (ks[1] == ((2-S[2]+256)&0xff)) { jq = Si[ks[1]]; if ((jq != 1) && (jq != 2)) { Kq = (jq - dq + 256)&0xff; doVote(first, second, i, A_s5_3, Kq, iv, weights[1], keylength); // votes[i][A_s5_3][Kq]++; } } } if ((S[1] != 2) && (S[2] != 0)) { j2 = (S[1] + S[2])&0xff; if (j2 < (q+i)) { t2 = (S[j2] + S[2])&0xff ; if ((t2 == (q+i)) && (Si[ks[1]] != 1) && (Si[ks[1]] != 2) && (Si[ks[1]] != j2)) { Kq = (Si[ks[1]] - dq + 256)&0xff; doVote(first, second, i, A_s3, Kq, iv, weights[1], keylength); // votes[i][A_s3][Kq]++; } } } if (S[1] == 2) { if ((q+i) == 4) { if (ks[1] == 0) { Kq = (Si[0] - dq + 256)&0xff; doVote(first, second, i, A_4_s13, Kq, iv, weights[1], keylength); // votes[i][A_4_s13][Kq]++; } else { if ((jj[1] == 2) && (Si[ks[1]] == 0)) { Kq = (Si[254] - dq+256)&0xff; doVote(first, second, i, A_4_u5_1, Kq, iv, weights[1], keylength); // votes[i][A_4_u5_1][Kq]++; } if ((jj[1] == 2) && (Si[ks[1]] == 2)) { Kq = (Si[255] - dq + 256)&0xff; doVote(first, second, i, A_4_u5_2, Kq, iv, weights[1], keylength); // votes[i][A_4_u5_2][Kq]++; } } } // We have to skip this attack } } } /* * Guess which key bytes could be strong and start actual computation of the key */ int PTW2_computeKey(PTW2_attackstate * state, uint8_t * keybuf, int keylen, int testlimit, int * bf, int validchars[][n], int attacks) { int strongbytes[KEYHSBYTES]; /* double normal[KEYHSBYTES]; double ausreisser[KEYHSBYTES]; doublesorthelper helper[KEYHSBYTES]; int simple, onestrong, twostrong; */ int i,j,t; uint8_t fullkeybuf[PTW2_KSBYTES]; uint8_t guessbuf[PTW2_KSBYTES]; sorthelper(*sh)[n-1]; PTW2_tableentry (*table)[n] = (PTW2_tableentry (*)[256]) alloca(sizeof(PTW2_tableentry) * n * keylen); PTW2_tableentry (*tablefirst)[n] = (PTW2_tableentry (*)[256]) alloca(sizeof(PTW2_tableentry) * n * keylen); PTW2_tableentry (*tablesecond)[n] = (PTW2_tableentry (*)[256]) alloca(sizeof(PTW2_tableentry) * n * keylen); tried=0; sh = NULL; if (table == NULL) { printf("could not allocate memory\n"); exit(-1); } if(!(attacks & NO_KLEIN)) { // Try the original klein attack first for (i = 0; i < keylen; i++) { bzero(&table[i][0], sizeof(PTW2_tableentry) * n); for (j = 0; j < n; j++) { table[i][j].b = j; } for (j = 0; j < state->packets_collected; j++) { // fullkeybuf[0] = state->allsessions[j].iv[0]; memcpy(fullkeybuf, state->allsessions[j].iv, 3 * sizeof(uint8_t)); guesskeybytes(i+3, fullkeybuf, state->allsessions[j].keystream, guessbuf, 1); table[i][guessbuf[0]].votes += state->allsessions[j].weight[i+2]; } qsort(&table[i][0], n, sizeof(PTW2_tableentry), &compare); j = 0; while(!validchars[i][table[i][j].b]) { j++; } // printf("guessing i = %d, b = %d\n", i, table[0][0].b); fullkeybuf[i+3] = table[i][j].b; } if (correct(state, &fullkeybuf[3], keylen)) { memcpy(keybuf, &fullkeybuf[3], keylen * sizeof(uint8_t)); // printf("hit without correction\n"); return 1; } } if(!(attacks & NO_PTW2)) { // First, init the tables for (i = 0; i < keylen; i++) { bzero(&table[i][0], sizeof(PTW2_tableentry) * n); bzero(&tablefirst[i][0], sizeof(PTW2_tableentry) * n); bzero(&tablesecond[i][0], sizeof(PTW2_tableentry) * n); for (j = 0; j < n; j++) { table[i][j].b = j; tablefirst[i][j].b = j; tablesecond[i][j].b = j; } } // printf("generating votes\n"); // Now, generate the votes for (i = 0; i < state->packets_collected; i++) { // fullkeybuf[0] = state->allsessions[j].iv[0]; genVotes(tablefirst, tablesecond, state->allsessions[i].iv, state->allsessions[i].keystream, state->allsessions[i].weight, keylen); } // Votes generated, now execute the attack // First, we need to decide on the last keybyte. Fill the table for the last keybyte for (i = 0; i < n; i++) { table[0][i].votes = tablefirst[keylen-1][i].votes; } qsort(&table[0][0], n, sizeof(PTW2_tableentry), &compare); // keybyte is now t t = table[0][0].b; // Now, correct the votes for (i = 0; i < keylen-1; i++) { for (j = 0; j < n; j++) { table[i][j].b = j; table[i][j].votes = (tablefirst[i][j].votes * coeffs[A_first]) + (tablesecond[i][(j+t)&0xff].votes * coeffs[A_second]); } // dumpTable(&table[i][0], i); qsort(&table[i][0], n, sizeof(PTW2_tableentry), &compare); strongbytes[i] = 0; } for (j = 0; j < n; j++) { table[keylen-1][j].b = j; table[keylen-1][j].votes = (tablefirst[keylen-1][j].votes * coeffs[A_first]); } // dumpTable(&table[keylen-1][0],keylen-1); qsort(&table[keylen-1][0], n, sizeof(PTW2_tableentry), &compare); strongbytes[keylen-1] = 0; // We can now start the usual key ranking thing sh = (sorthelper (*)[255]) alloca(sizeof(sorthelper) * (n-1) * (keylen-1)); if (sh == NULL) { printf("could not allocate memory\n"); } for (i = 0; i < keylen-1; i++) { for (j = 1; j < n; j++) { sh[i][j-1].distance = table[i][0].votes - table[i][j].votes; sh[i][j-1].value = table[i][j].b; sh[i][j-1].keybyte = i; } } qsort(sh, (n-1)*(keylen-1), sizeof(sorthelper), &comparesorthelper); if (doComputation(state, keybuf, keylen, table, (sorthelper *) sh, strongbytes, testlimit, bf, validchars)) { return 1; } } return 0; } /* * Add a new session to the attack * state - state of attack * iv - IV used in the session * keystream - recovered keystream from the session */ int PTW2_addsession(PTW2_attackstate * state, uint8_t * iv, uint8_t * keystream, uint8_t * weight, int total) { int i,j,k; int il; int ir; // uint8_t buf[PTW2_KEYHSBYTES]; i = (iv[0] << 16) | (iv[1] << 8) | (iv[2]); il = i/8; ir = 1 << (i%8); if ((state->seen_iv[il] & ir) == 0) { state->seen_iv[il] |= ir; for (j = 0; j < total; j++) { state->packets_collected++; // guesskeybytes(IVBYTES, iv, &keystream[KSBYTES*j], buf, PTW_KEYHSBYTES); // for (i = 0; i < KEYHSBYTES; i++) { // state->table[i][buf[i]].votes += weight[j]; // } if (state->allsessions_size < state->packets_collected) { state->allsessions_size = state->allsessions_size << 1; state->allsessions = (PTW2_session *) realloc(state->allsessions, state->allsessions_size * sizeof(PTW2_session)); if (state->allsessions == NULL) { printf("could not allocate memory\n"); exit(-1); } } memcpy(state->allsessions[state->packets_collected-1].iv, iv, IVBYTES); memcpy(state->allsessions[state->packets_collected-1].keystream, &keystream[KSBYTES*j], KSBYTES); // memcpy(state->allsessions[state->packets_collected-1].weight, &weight[KSBYTS*j], KSBYTES); for (k = 0; k < KSBYTES; k++) { state->allsessions[state->packets_collected-1].weight[k] = weight[KSBYTES*j+k]; } } if ((state->sessions_collected < CONTROLSESSIONS)) { memcpy(state->sessions[state->sessions_collected].iv, iv, IVBYTES); memcpy(state->sessions[state->sessions_collected].keystream, keystream, KSBYTES); state->sessions_collected++; } return 1; } else { return 0; } } /* * Allocate a new attackstate */ PTW2_attackstate * PTW2_newattackstate() { int i,k; PTW2_attackstate * state = NULL; state = (PTW2_attackstate *) malloc(sizeof(PTW2_attackstate)); if (state == NULL) { return NULL; } bzero(state, sizeof(PTW2_attackstate)); for (i = 0; i < PTW2_KEYHSBYTES; i++) { for (k = 0; k < n; k++) { state->tablefirst[i][k].b = k; state->tablesecond[i][k].b = k; } } state->allsessions = (PTW2_session *) malloc(4096 * sizeof(PTW2_session)); state->allsessions_size = 4096; if (state->allsessions == NULL) { printf("could not allocate memory\n"); exit(-1); } return state; } /* * Free an allocated attackstate */ void PTW2_freeattackstate(PTW2_attackstate * state) { free(state->allsessions); free(state); return; } PTW2_attackstate *PTW2_copyattackstate(PTW2_attackstate *state) { PTW2_attackstate *r = (PTW2_attackstate *) malloc(sizeof(PTW2_attackstate)); if (r == NULL) return NULL; memcpy(r, state, sizeof(PTW2_attackstate)); r->allsessions = (PTW2_session *) malloc(sizeof(PTW2_session) * r->allsessions_size); if (r->allsessions == NULL) { free(r); return NULL; } memcpy(r->allsessions, state->allsessions, sizeof(PTW2_session) * r->allsessions_size); return r; } kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-crctable.h0000664000175000017500000002343512124602454023443 0ustar dragorndragorn#ifndef _CRCTABLE_H #define _CRCTABLE_H const unsigned long int crc_tbl[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; const unsigned char crc_chop_tbl[256][4] = { { 0x26,0x70,0x6A,0x0F }, { 0x67,0x76,0x1B,0xD4 }, { 0xE5,0x7A,0xF9,0x62 }, { 0xA4,0x7C,0x88,0xB9 }, { 0xA0,0x65,0x4C,0xD4 }, { 0xE1,0x63,0x3D,0x0F }, { 0x63,0x6F,0xDF,0xB9 }, { 0x22,0x69,0xAE,0x62 }, { 0x6B,0x5D,0x57,0x62 }, { 0x2A,0x5B,0x26,0xB9 }, { 0xA8,0x57,0xC4,0x0F }, { 0xE9,0x51,0xB5,0xD4 }, { 0xED,0x48,0x71,0xB9 }, { 0xAC,0x4E,0x00,0x62 }, { 0x2E,0x42,0xE2,0xD4 }, { 0x6F,0x44,0x93,0x0F }, { 0xBC,0x2A,0x10,0xD5 }, { 0xFD,0x2C,0x61,0x0E }, { 0x7F,0x20,0x83,0xB8 }, { 0x3E,0x26,0xF2,0x63 }, { 0x3A,0x3F,0x36,0x0E }, { 0x7B,0x39,0x47,0xD5 }, { 0xF9,0x35,0xA5,0x63 }, { 0xB8,0x33,0xD4,0xB8 }, { 0xF1,0x07,0x2D,0xB8 }, { 0xB0,0x01,0x5C,0x63 }, { 0x32,0x0D,0xBE,0xD5 }, { 0x73,0x0B,0xCF,0x0E }, { 0x77,0x12,0x0B,0x63 }, { 0x36,0x14,0x7A,0xB8 }, { 0xB4,0x18,0x98,0x0E }, { 0xF5,0x1E,0xE9,0xD5 }, { 0x53,0xC3,0xEF,0x60 }, { 0x12,0xC5,0x9E,0xBB }, { 0x90,0xC9,0x7C,0x0D }, { 0xD1,0xCF,0x0D,0xD6 }, { 0xD5,0xD6,0xC9,0xBB }, { 0x94,0xD0,0xB8,0x60 }, { 0x16,0xDC,0x5A,0xD6 }, { 0x57,0xDA,0x2B,0x0D }, { 0x1E,0xEE,0xD2,0x0D }, { 0x5F,0xE8,0xA3,0xD6 }, { 0xDD,0xE4,0x41,0x60 }, { 0x9C,0xE2,0x30,0xBB }, { 0x98,0xFB,0xF4,0xD6 }, { 0xD9,0xFD,0x85,0x0D }, { 0x5B,0xF1,0x67,0xBB }, { 0x1A,0xF7,0x16,0x60 }, { 0xC9,0x99,0x95,0xBA }, { 0x88,0x9F,0xE4,0x61 }, { 0x0A,0x93,0x06,0xD7 }, { 0x4B,0x95,0x77,0x0C }, { 0x4F,0x8C,0xB3,0x61 }, { 0x0E,0x8A,0xC2,0xBA }, { 0x8C,0x86,0x20,0x0C }, { 0xCD,0x80,0x51,0xD7 }, { 0x84,0xB4,0xA8,0xD7 }, { 0xC5,0xB2,0xD9,0x0C }, { 0x47,0xBE,0x3B,0xBA }, { 0x06,0xB8,0x4A,0x61 }, { 0x02,0xA1,0x8E,0x0C }, { 0x43,0xA7,0xFF,0xD7 }, { 0xC1,0xAB,0x1D,0x61 }, { 0x80,0xAD,0x6C,0xBA }, { 0xCC,0x16,0x61,0xD0 }, { 0x8D,0x10,0x10,0x0B }, { 0x0F,0x1C,0xF2,0xBD }, { 0x4E,0x1A,0x83,0x66 }, { 0x4A,0x03,0x47,0x0B }, { 0x0B,0x05,0x36,0xD0 }, { 0x89,0x09,0xD4,0x66 }, { 0xC8,0x0F,0xA5,0xBD }, { 0x81,0x3B,0x5C,0xBD }, { 0xC0,0x3D,0x2D,0x66 }, { 0x42,0x31,0xCF,0xD0 }, { 0x03,0x37,0xBE,0x0B }, { 0x07,0x2E,0x7A,0x66 }, { 0x46,0x28,0x0B,0xBD }, { 0xC4,0x24,0xE9,0x0B }, { 0x85,0x22,0x98,0xD0 }, { 0x56,0x4C,0x1B,0x0A }, { 0x17,0x4A,0x6A,0xD1 }, { 0x95,0x46,0x88,0x67 }, { 0xD4,0x40,0xF9,0xBC }, { 0xD0,0x59,0x3D,0xD1 }, { 0x91,0x5F,0x4C,0x0A }, { 0x13,0x53,0xAE,0xBC }, { 0x52,0x55,0xDF,0x67 }, { 0x1B,0x61,0x26,0x67 }, { 0x5A,0x67,0x57,0xBC }, { 0xD8,0x6B,0xB5,0x0A }, { 0x99,0x6D,0xC4,0xD1 }, { 0x9D,0x74,0x00,0xBC }, { 0xDC,0x72,0x71,0x67 }, { 0x5E,0x7E,0x93,0xD1 }, { 0x1F,0x78,0xE2,0x0A }, { 0xB9,0xA5,0xE4,0xBF }, { 0xF8,0xA3,0x95,0x64 }, { 0x7A,0xAF,0x77,0xD2 }, { 0x3B,0xA9,0x06,0x09 }, { 0x3F,0xB0,0xC2,0x64 }, { 0x7E,0xB6,0xB3,0xBF }, { 0xFC,0xBA,0x51,0x09 }, { 0xBD,0xBC,0x20,0xD2 }, { 0xF4,0x88,0xD9,0xD2 }, { 0xB5,0x8E,0xA8,0x09 }, { 0x37,0x82,0x4A,0xBF }, { 0x76,0x84,0x3B,0x64 }, { 0x72,0x9D,0xFF,0x09 }, { 0x33,0x9B,0x8E,0xD2 }, { 0xB1,0x97,0x6C,0x64 }, { 0xF0,0x91,0x1D,0xBF }, { 0x23,0xFF,0x9E,0x65 }, { 0x62,0xF9,0xEF,0xBE }, { 0xE0,0xF5,0x0D,0x08 }, { 0xA1,0xF3,0x7C,0xD3 }, { 0xA5,0xEA,0xB8,0xBE }, { 0xE4,0xEC,0xC9,0x65 }, { 0x66,0xE0,0x2B,0xD3 }, { 0x27,0xE6,0x5A,0x08 }, { 0x6E,0xD2,0xA3,0x08 }, { 0x2F,0xD4,0xD2,0xD3 }, { 0xAD,0xD8,0x30,0x65 }, { 0xEC,0xDE,0x41,0xBE }, { 0xE8,0xC7,0x85,0xD3 }, { 0xA9,0xC1,0xF4,0x08 }, { 0x2B,0xCD,0x16,0xBE }, { 0x6A,0xCB,0x67,0x65 }, { 0xB3,0xBB,0x0D,0x6A }, { 0xF2,0xBD,0x7C,0xB1 }, { 0x70,0xB1,0x9E,0x07 }, { 0x31,0xB7,0xEF,0xDC }, { 0x35,0xAE,0x2B,0xB1 }, { 0x74,0xA8,0x5A,0x6A }, { 0xF6,0xA4,0xB8,0xDC }, { 0xB7,0xA2,0xC9,0x07 }, { 0xFE,0x96,0x30,0x07 }, { 0xBF,0x90,0x41,0xDC }, { 0x3D,0x9C,0xA3,0x6A }, { 0x7C,0x9A,0xD2,0xB1 }, { 0x78,0x83,0x16,0xDC }, { 0x39,0x85,0x67,0x07 }, { 0xBB,0x89,0x85,0xB1 }, { 0xFA,0x8F,0xF4,0x6A }, { 0x29,0xE1,0x77,0xB0 }, { 0x68,0xE7,0x06,0x6B }, { 0xEA,0xEB,0xE4,0xDD }, { 0xAB,0xED,0x95,0x06 }, { 0xAF,0xF4,0x51,0x6B }, { 0xEE,0xF2,0x20,0xB0 }, { 0x6C,0xFE,0xC2,0x06 }, { 0x2D,0xF8,0xB3,0xDD }, { 0x64,0xCC,0x4A,0xDD }, { 0x25,0xCA,0x3B,0x06 }, { 0xA7,0xC6,0xD9,0xB0 }, { 0xE6,0xC0,0xA8,0x6B }, { 0xE2,0xD9,0x6C,0x06 }, { 0xA3,0xDF,0x1D,0xDD }, { 0x21,0xD3,0xFF,0x6B }, { 0x60,0xD5,0x8E,0xB0 }, { 0xC6,0x08,0x88,0x05 }, { 0x87,0x0E,0xF9,0xDE }, { 0x05,0x02,0x1B,0x68 }, { 0x44,0x04,0x6A,0xB3 }, { 0x40,0x1D,0xAE,0xDE }, { 0x01,0x1B,0xDF,0x05 }, { 0x83,0x17,0x3D,0xB3 }, { 0xC2,0x11,0x4C,0x68 }, { 0x8B,0x25,0xB5,0x68 }, { 0xCA,0x23,0xC4,0xB3 }, { 0x48,0x2F,0x26,0x05 }, { 0x09,0x29,0x57,0xDE }, { 0x0D,0x30,0x93,0xB3 }, { 0x4C,0x36,0xE2,0x68 }, { 0xCE,0x3A,0x00,0xDE }, { 0x8F,0x3C,0x71,0x05 }, { 0x5C,0x52,0xF2,0xDF }, { 0x1D,0x54,0x83,0x04 }, { 0x9F,0x58,0x61,0xB2 }, { 0xDE,0x5E,0x10,0x69 }, { 0xDA,0x47,0xD4,0x04 }, { 0x9B,0x41,0xA5,0xDF }, { 0x19,0x4D,0x47,0x69 }, { 0x58,0x4B,0x36,0xB2 }, { 0x11,0x7F,0xCF,0xB2 }, { 0x50,0x79,0xBE,0x69 }, { 0xD2,0x75,0x5C,0xDF }, { 0x93,0x73,0x2D,0x04 }, { 0x97,0x6A,0xE9,0x69 }, { 0xD6,0x6C,0x98,0xB2 }, { 0x54,0x60,0x7A,0x04 }, { 0x15,0x66,0x0B,0xDF }, { 0x59,0xDD,0x06,0xB5 }, { 0x18,0xDB,0x77,0x6E }, { 0x9A,0xD7,0x95,0xD8 }, { 0xDB,0xD1,0xE4,0x03 }, { 0xDF,0xC8,0x20,0x6E }, { 0x9E,0xCE,0x51,0xB5 }, { 0x1C,0xC2,0xB3,0x03 }, { 0x5D,0xC4,0xC2,0xD8 }, { 0x14,0xF0,0x3B,0xD8 }, { 0x55,0xF6,0x4A,0x03 }, { 0xD7,0xFA,0xA8,0xB5 }, { 0x96,0xFC,0xD9,0x6E }, { 0x92,0xE5,0x1D,0x03 }, { 0xD3,0xE3,0x6C,0xD8 }, { 0x51,0xEF,0x8E,0x6E }, { 0x10,0xE9,0xFF,0xB5 }, { 0xC3,0x87,0x7C,0x6F }, { 0x82,0x81,0x0D,0xB4 }, { 0x00,0x8D,0xEF,0x02 }, { 0x41,0x8B,0x9E,0xD9 }, { 0x45,0x92,0x5A,0xB4 }, { 0x04,0x94,0x2B,0x6F }, { 0x86,0x98,0xC9,0xD9 }, { 0xC7,0x9E,0xB8,0x02 }, { 0x8E,0xAA,0x41,0x02 }, { 0xCF,0xAC,0x30,0xD9 }, { 0x4D,0xA0,0xD2,0x6F }, { 0x0C,0xA6,0xA3,0xB4 }, { 0x08,0xBF,0x67,0xD9 }, { 0x49,0xB9,0x16,0x02 }, { 0xCB,0xB5,0xF4,0xB4 }, { 0x8A,0xB3,0x85,0x6F }, { 0x2C,0x6E,0x83,0xDA }, { 0x6D,0x68,0xF2,0x01 }, { 0xEF,0x64,0x10,0xB7 }, { 0xAE,0x62,0x61,0x6C }, { 0xAA,0x7B,0xA5,0x01 }, { 0xEB,0x7D,0xD4,0xDA }, { 0x69,0x71,0x36,0x6C }, { 0x28,0x77,0x47,0xB7 }, { 0x61,0x43,0xBE,0xB7 }, { 0x20,0x45,0xCF,0x6C }, { 0xA2,0x49,0x2D,0xDA }, { 0xE3,0x4F,0x5C,0x01 }, { 0xE7,0x56,0x98,0x6C }, { 0xA6,0x50,0xE9,0xB7 }, { 0x24,0x5C,0x0B,0x01 }, { 0x65,0x5A,0x7A,0xDA }, { 0xB6,0x34,0xF9,0x00 }, { 0xF7,0x32,0x88,0xDB }, { 0x75,0x3E,0x6A,0x6D }, { 0x34,0x38,0x1B,0xB6 }, { 0x30,0x21,0xDF,0xDB }, { 0x71,0x27,0xAE,0x00 }, { 0xF3,0x2B,0x4C,0xB6 }, { 0xB2,0x2D,0x3D,0x6D }, { 0xFB,0x19,0xC4,0x6D }, { 0xBA,0x1F,0xB5,0xB6 }, { 0x38,0x13,0x57,0x00 }, { 0x79,0x15,0x26,0xDB }, { 0x7D,0x0C,0xE2,0xB6 }, { 0x3C,0x0A,0x93,0x6D }, { 0xBE,0x06,0x71,0xDB }, { 0xFF,0x00,0x00,0x00 } }; #endif /* crctable.h */ kismet-2013-03-R1b/restricted-plugin-ptw/aircrack-crypto.h0000664000175000017500000002270312124602454023201 0ustar dragorndragorn#ifndef _CRYPTO_H #define _CRYPTO_H #ifndef uint8 #define uint8 unsigned char #endif #ifndef uint32 #define uint32 unsigned long int #endif #include #include // We don't use EVP. Bite me #include #include #define S_LLC_SNAP "\xAA\xAA\x03\x00\x00\x00" #define S_LLC_SNAP_ARP (S_LLC_SNAP "\x08\x06") #define S_LLC_SNAP_IP (S_LLC_SNAP "\x08\x00") #define S_LLC_SNAP_SPANTREE "\x42\x42\x03\x00\x00\x00\x00\x00" #define S_LLC_SNAP_CDP "\xAA\xAA\x03\x00\x00\x0C\x20" #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define TYPE_ARP 0 #define TYPE_IP 1 #define NULL_MAC (uchar*)"\x00\x00\x00\x00\x00\x00" #define BROADCAST (uchar*)"\xFF\xFF\xFF\xFF\xFF\xFF" #define SPANTREE (uchar*)"\x01\x80\xC2\x00\x00\x00" #define CDP_VTP (uchar*)"\x01\x00\x0C\xCC\xCC\xCC" #define IEEE80211_FC0_SUBTYPE_MASK 0xf0 #define IEEE80211_FC0_SUBTYPE_SHIFT 4 /* for TYPE_DATA (bit combination) */ #define IEEE80211_FC0_SUBTYPE_QOS 0x80 #define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 #define GET_SUBTYPE(fc) \ ( ( (fc) & IEEE80211_FC0_SUBTYPE_MASK ) >> IEEE80211_FC0_SUBTYPE_SHIFT ) \ << IEEE80211_FC0_SUBTYPE_SHIFT #define uchar unsigned char #define ROL32( A, n ) \ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) #define ROR32( A, n ) ROL32( (A), 32-(n) ) struct WPA_ST_info { struct WPA_ST_info *next; /* next supplicant */ uchar stmac[6]; /* supplicant MAC */ uchar bssid[6]; /* authenticator MAC */ uchar snonce[32]; /* supplicant nonce */ uchar anonce[32]; /* authenticator nonce */ uchar keymic[20]; /* eapol frame MIC */ uchar eapol[256]; /* eapol frame contents */ uchar ptk[80]; /* pairwise transcient key */ int eapol_size; /* eapol frame size */ unsigned long t_crc; /* last ToDS frame CRC */ unsigned long f_crc; /* last FromDS frame CRC */ int keyver, valid_ptk; }; struct Michael { unsigned long key0; unsigned long key1; unsigned long left; unsigned long right; unsigned long nBytesInM; unsigned long message; unsigned char mic[8]; }; // typedef unsigned char byte; /* 8-bit byte (octet) */ // typedef unsigned short u16b; /* 16-bit unsigned word */ // typedef unsigned long u32b; /* 32-bit unsigned word */ // /* macros for extraction/creation of byte/u16b values */ // #define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) // #define Lo8(v16) ((byte)( (v16) & 0x00FF)) // #define Hi8(v16) ((byte)(((v16) >> 8) & 0x00FF)) // #define Lo16(v32) ((u16b)( (v32) & 0xFFFF)) // #define Hi16(v32) ((u16b)(((v32) >>16) & 0xFFFF)) // #define Mk16(hi,lo) ((lo) ^ (((u16b)(hi)) << 8)) // /* select the Nth 16-bit word of the Temporal Key byte array TK[] */ // #define TK16(N) Mk16(TK[2*(N)+1],TK[2*(N)]) // /* S-box lookup: 16 bits --> 16 bits */ // #define _S_(v16) (Sbox[0][Lo8(v16)] ^ Sbox[1][Hi8(v16)]) // /* fixed algorithm "parameters" */ // #define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ // #define TA_SIZE 6 /* 48-bit transmitter address */ // #define TK_SIZE 16 /* 128-bit Temporal Key */ // #define P1K_SIZE 10 /* 80-bit Phase1 key */ // #define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ /* 2-byte by 2-byte subset of the full AES S-box table */ // const u16b TkipSbox[2][256]= /* Sbox for hash (can be in ROM) */ // {{ // 0xC6A5,0xF884,0xEE99,0xF68D,0xFF0D,0xD6BD,0xDEB1,0x9154, // 0x6050,0x0203,0xCEA9,0x567D,0xE719,0xB562,0x4DE6,0xEC9A, // 0x8F45,0x1F9D,0x8940,0xFA87,0xEF15,0xB2EB,0x8EC9,0xFB0B, // 0x41EC,0xB367,0x5FFD,0x45EA,0x23BF,0x53F7,0xE496,0x9B5B, // 0x75C2,0xE11C,0x3DAE,0x4C6A,0x6C5A,0x7E41,0xF502,0x834F, // 0x685C,0x51F4,0xD134,0xF908,0xE293,0xAB73,0x6253,0x2A3F, // 0x080C,0x9552,0x4665,0x9D5E,0x3028,0x37A1,0x0A0F,0x2FB5, // 0x0E09,0x2436,0x1B9B,0xDF3D,0xCD26,0x4E69,0x7FCD,0xEA9F, // 0x121B,0x1D9E,0x5874,0x342E,0x362D,0xDCB2,0xB4EE,0x5BFB, // 0xA4F6,0x764D,0xB761,0x7DCE,0x527B,0xDD3E,0x5E71,0x1397, // 0xA6F5,0xB968,0x0000,0xC12C,0x4060,0xE31F,0x79C8,0xB6ED, // 0xD4BE,0x8D46,0x67D9,0x724B,0x94DE,0x98D4,0xB0E8,0x854A, // 0xBB6B,0xC52A,0x4FE5,0xED16,0x86C5,0x9AD7,0x6655,0x1194, // 0x8ACF,0xE910,0x0406,0xFE81,0xA0F0,0x7844,0x25BA,0x4BE3, // 0xA2F3,0x5DFE,0x80C0,0x058A,0x3FAD,0x21BC,0x7048,0xF104, // 0x63DF,0x77C1,0xAF75,0x4263,0x2030,0xE51A,0xFD0E,0xBF6D, // 0x814C,0x1814,0x2635,0xC32F,0xBEE1,0x35A2,0x88CC,0x2E39, // 0x9357,0x55F2,0xFC82,0x7A47,0xC8AC,0xBAE7,0x322B,0xE695, // 0xC0A0,0x1998,0x9ED1,0xA37F,0x4466,0x547E,0x3BAB,0x0B83, // 0x8CCA,0xC729,0x6BD3,0x283C,0xA779,0xBCE2,0x161D,0xAD76, // 0xDB3B,0x6456,0x744E,0x141E,0x92DB,0x0C0A,0x486C,0xB8E4, // 0x9F5D,0xBD6E,0x43EF,0xC4A6,0x39A8,0x31A4,0xD337,0xF28B, // 0xD532,0x8B43,0x6E59,0xDAB7,0x018C,0xB164,0x9CD2,0x49E0, // 0xD8B4,0xACFA,0xF307,0xCF25,0xCAAF,0xF48E,0x47E9,0x1018, // 0x6FD5,0xF088,0x4A6F,0x5C72,0x3824,0x57F1,0x73C7,0x9751, // 0xCB23,0xA17C,0xE89C,0x3E21,0x96DD,0x61DC,0x0D86,0x0F85, // 0xE090,0x7C42,0x71C4,0xCCAA,0x90D8,0x0605,0xF701,0x1C12, // 0xC2A3,0x6A5F,0xAEF9,0x69D0,0x1791,0x9958,0x3A27,0x27B9, // 0xD938,0xEB13,0x2BB3,0x2233,0xD2BB,0xA970,0x0789,0x33A7, // 0x2DB6,0x3C22,0x1592,0xC920,0x8749,0xAAFF,0x5078,0xA57A, // 0x038F,0x59F8,0x0980,0x1A17,0x65DA,0xD731,0x84C6,0xD0B8, // 0x82C3,0x29B0,0x5A77,0x1E11,0x7BCB,0xA8FC,0x6DD6,0x2C3A, // }, // { /* second half of table is byte-reversed version of first! */ // 0xA5C6,0x84F8,0x99EE,0x8DF6,0x0DFF,0xBDD6,0xB1DE,0x5491, // 0x5060,0x0302,0xA9CE,0x7D56,0x19E7,0x62B5,0xE64D,0x9AEC, // 0x458F,0x9D1F,0x4089,0x87FA,0x15EF,0xEBB2,0xC98E,0x0BFB, // 0xEC41,0x67B3,0xFD5F,0xEA45,0xBF23,0xF753,0x96E4,0x5B9B, // 0xC275,0x1CE1,0xAE3D,0x6A4C,0x5A6C,0x417E,0x02F5,0x4F83, // 0x5C68,0xF451,0x34D1,0x08F9,0x93E2,0x73AB,0x5362,0x3F2A, // 0x0C08,0x5295,0x6546,0x5E9D,0x2830,0xA137,0x0F0A,0xB52F, // 0x090E,0x3624,0x9B1B,0x3DDF,0x26CD,0x694E,0xCD7F,0x9FEA, // 0x1B12,0x9E1D,0x7458,0x2E34,0x2D36,0xB2DC,0xEEB4,0xFB5B, // 0xF6A4,0x4D76,0x61B7,0xCE7D,0x7B52,0x3EDD,0x715E,0x9713, // 0xF5A6,0x68B9,0x0000,0x2CC1,0x6040,0x1FE3,0xC879,0xEDB6, // 0xBED4,0x468D,0xD967,0x4B72,0xDE94,0xD498,0xE8B0,0x4A85, // 0x6BBB,0x2AC5,0xE54F,0x16ED,0xC586,0xD79A,0x5566,0x9411, // 0xCF8A,0x10E9,0x0604,0x81FE,0xF0A0,0x4478,0xBA25,0xE34B, // 0xF3A2,0xFE5D,0xC080,0x8A05,0xAD3F,0xBC21,0x4870,0x04F1, // 0xDF63,0xC177,0x75AF,0x6342,0x3020,0x1AE5,0x0EFD,0x6DBF, // 0x4C81,0x1418,0x3526,0x2FC3,0xE1BE,0xA235,0xCC88,0x392E, // 0x5793,0xF255,0x82FC,0x477A,0xACC8,0xE7BA,0x2B32,0x95E6, // 0xA0C0,0x9819,0xD19E,0x7FA3,0x6644,0x7E54,0xAB3B,0x830B, // 0xCA8C,0x29C7,0xD36B,0x3C28,0x79A7,0xE2BC,0x1D16,0x76AD, // 0x3BDB,0x5664,0x4E74,0x1E14,0xDB92,0x0A0C,0x6C48,0xE4B8, // 0x5D9F,0x6EBD,0xEF43,0xA6C4,0xA839,0xA431,0x37D3,0x8BF2, // 0x32D5,0x438B,0x596E,0xB7DA,0x8C01,0x64B1,0xD29C,0xE049, // 0xB4D8,0xFAAC,0x07F3,0x25CF,0xAFCA,0x8EF4,0xE947,0x1810, // 0xD56F,0x88F0,0x6F4A,0x725C,0x2438,0xF157,0xC773,0x5197, // 0x23CB,0x7CA1,0x9CE8,0x213E,0xDD96,0xDC61,0x860D,0x850F, // 0x90E0,0x427C,0xC471,0xAACC,0xD890,0x0506,0x01F7,0x121C, // 0xA3C2,0x5F6A,0xF9AE,0xD069,0x9117,0x5899,0x273A,0xB927, // 0x38D9,0x13EB,0xB32B,0x3322,0xBBD2,0x70A9,0x8907,0xA733, // 0xB62D,0x223C,0x9215,0x20C9,0x4987,0xFFAA,0x7850,0x7AA5, // 0x8F03,0xF859,0x8009,0x171A,0xDA65,0x31D7,0xC684,0xB8D0, // 0xC382,0xB029,0x775A,0x111E,0xCB7B,0xFCA8,0xD66D,0x3A2C, // } // }; /* Used for own RC4 implementation */ struct rc4_state { int x, y, m[256]; }; struct AP_info; void calc_pmk( char *key, char *essid, unsigned char pmk[40] ); int decrypt_wep( unsigned char *data, int len, unsigned char *key, int keylen ); int encrypt_wep( unsigned char *data, int len, unsigned char *key, int keylen ); int check_crc_buf( unsigned char *buf, int len ); int calc_crc_buf( unsigned char *buf, int len ); void calc_mic(struct AP_info *ap, unsigned char *pmk, unsigned char *ptk, unsigned char *mic); int known_clear(uint8_t *clear, int *clen, unsigned char *weight, unsigned char *wh, int len); int add_crc32(unsigned char* data, int length); int add_crc32_plain(unsigned char* data, int length); int is_ipv6(uint8_t *wh); int is_dhcp_discover(uint8_t *wh, int len); int calc_tkip_ppk( unsigned char *h80211, int caplen, unsigned char TK1[16], unsigned char key[16] ); int decrypt_tkip( unsigned char *h80211, int caplen, unsigned char TK1[16] ); int decrypt_ccmp( unsigned char *h80211, int caplen, unsigned char TK1[16] ); int calc_ptk( struct WPA_ST_info *wpa, uchar pmk[32] ); int calc_tkip_mic(uchar* packet, int length, uchar ptk[80], uchar value[8]); int michael_test(uchar key[8], uchar *message, int length, uchar out[8]); int calc_tkip_mic_key(uchar* packet, int length, uchar key[8]); #endif /* crypto.h */ kismet-2013-03-R1b/restricted-plugin-ptw/README0000664000175000017500000001004012124602454020602 0ustar dragorndragornKismet-PTW 1. What is Kismet-PTW 2. Caveats 3. Compiling 4. Installing 5. Using 1. What is Kismet-PTW Kismet-PTW is a Kismet plugin which performs the Aircrack-NG PTW attack against data captured by Kismet. The Aircrack-NG PTW attack exploits flaws in WEP to expose the original keystream. Because the PTW attack needs relatively few packets (50,000 to 100,000) and is relatively CPU cheap, it makes sense to include this as an automatic feature. While Aircrack-NG can use injection to accelerate the rate at which packets are generated, increasing the chances of deriving the key, the Kismet-PTW version is 100% passive. Kismet will NOT inject packets or actively attack a network, with this plugin it will simply examine the data it has already recorded. The code for the PTW attack is directly extracted from Aircrack-NG, this plugin simply wraps the Aircrack-NG library into a form Kismet can use directly. For complete info about the PTW attack or Aircrack, see the Aircrack-NG project at: http://www.aircrack-ng.org 2. Caveats Memory Usage Because this plugin needs to store fragments of the packet data, it can dramatically increase the amount of memory Kismet uses. Memory usage is mitigated with timeout factors; if a network generates no WEP data in 30 minutes, the existing WEP data will be forgotten. CPU Usage Similarly, this will cause the CPU requirements of Kismet to rise considerably. The PTW calculations are run only at intervals when there have been sufficient new packets (1000 packets of known types and 5000 packets of unknown types), but during the calculations the load may be considerable. Packet Generation Kismet will not spoof packets or cause the network to increase the generation of packets. This may prevent the attack from working as quickly (or at all), depending on the network traffic generated by a network. Usage and Legality Using this against a network that is not your own is a Bad Idea. No support will be given for using this plugin as a means to gain access to a network. 3. Compiling Compiling the Kismet-PTW plugin requires the Kismet source be installed and configured. By default, Kismet-PTW expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-ptw/ KIS_SRC_DIR=/home/foo/src/kismet make 4. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-ptw KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-ptw make userinstall 5. Using Kismet-PTW is essentially automated. Once loaded, it will gather IV information for any WEP encrypted network detected. There is no kismet-client side plugin - WEP key disclosures will be registered as an alert, and the key and progress information will be shown in the network details. While running, Kismet-PTW will put the IV counts into the network as WEP-PTW-IV (number of packets seen with guessable IVs, such as ARP packets) and WEP-PTW-UNK (number of packets seen without guessable characteristics). Every 5,000 packets collected will trigger a PTW cracking attempt on the gathered data. If the PTW attack is successful, an IDS alert will be raised, and a WEP-PTW field will be added to the network containing the WEP key. Network fields can be viewed under Network Details in the Kismet UI and will be logged in the nettxt and netxml files. Networks which have not generated any data packets in 30 minutes will be "forgotten"; That is, their PTW records will be cleared, to prevent Kismet from using an obscene amount of RAM. kismet-2013-03-R1b/packetsource_pcap.cc0000664000175000017500000011117112124602454017457 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include "gpscore.h" #ifdef HAVE_LINUX_WIRELESS // Because some kernels include ethtool which breaks horribly... // The stock ones don't but others seem to typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long u64; #include #include #include #endif #ifdef SYS_DARWIN #include #include #include extern "C" { #include #include } #endif #if defined(SYS_OPENBSD) || defined(SYS_NETBSD) #include #include #include #include #include #include #ifdef HAVE_RADIOTAP #include #include #include #endif #endif #ifdef SYS_FREEBSD #include #include #include #ifdef HAVE_RADIOTAP #include #include #endif #endif #include "util.h" #include "endian_magic.h" #include "packetsourcetracker.h" #include "packetsource_pcap.h" #include "tcpdump-extract.h" #ifdef HAVE_LIBPCAP // This is such a bad thing to do... // #include // Pcap global callback structs, these get filled in by the pcap callback. // NON-THREAD-SAFE, if we ever use threads. pcap_pkthdr callback_header; u_char callback_data[MAX_PACKET_LEN]; int PacketSource_Pcap::OpenSource() { char errstr[STATUS_MAX] = ""; last_channel = 0; char *unconst = strdup(interface.c_str()); pd = pcap_open_live(unconst, MAX_PACKET_LEN, 1, 1000, errstr); free(unconst); if (strlen(errstr) > 0 || pd == NULL) { globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } error = 0; paused = 0; errstr[0] = '\0'; num_packets = 0; // Anything but windows and linux #if defined (SYS_OPENBSD) || defined(SYS_NETBSD) || defined(SYS_FREEBSD) \ || defined(SYS_DARWIN) // Set the DLT in the order of what we want least, since the last one we // set will stick pcap_set_datalink(pd, DLT_IEEE802_11); pcap_set_datalink(pd, DLT_IEEE802_11_RADIO_AVS); pcap_set_datalink(pd, DLT_IEEE802_11_RADIO); // Hack to re-enable promisc mode since changing the DLT seems to make it // drop it on some bsd pcap implementations ioctl(pcap_get_selectable_fd(pd), BIOCPROMISC, NULL); // Hack to set the fd to IOIMMEDIATE, to solve problems with select() on bpf // devices on BSD int v = 1; ioctl(pcap_get_selectable_fd(pd), BIOCIMMEDIATE, &v); #endif if (DatalinkType() < 0) { pcap_close(pd); return -1; } #ifdef HAVE_PCAP_NONBLOCK pcap_setnonblock(pd, 1, errstr); #elif !defined(SYS_OPENBSD) && defined(HAVE_PCAP_GETSELFD) // do something clever (Thanks to Guy Harris for suggesting this). int save_mode = fcntl(pcap_get_selectable_fd(pd), F_GETFL, 0); if (fcntl(pcap_get_selectable_fd(pd), F_SETFL, save_mode | O_NONBLOCK) < 0) { snprintf(errstr, 1024, "fcntl failed, errno %d (%s)", errno, strerror(errno)); } #endif if (strlen(errstr) > 0) { globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); if (pd != NULL) pcap_close(pd); return 0; } return 1; } int PacketSource_Pcap::CloseSource() { if (pd != NULL) pcap_close(pd); pd = NULL; return 1; } int PacketSource_Pcap::DatalinkType() { char errstr[STATUS_MAX] = ""; if (pd == NULL) return -1; datalink_type = pcap_datalink(pd); // Known good pcap generic header types if (datalink_type == DLT_PRISM_HEADER || datalink_type == DLT_IEEE802_11_RADIO || datalink_type == DLT_IEEE802_11_RADIO_AVS || datalink_type == DLT_IEEE802_11 || datalink_type == DLT_PPI) return 1; if (datalink_type == DLT_EN10MB && override_dlt >= 0) { _MSG("pcap reported netlink type 1 (EN10MB) for " + interface + ", but " "Kismet will override it with netlink " + IntToString(override_dlt), MSGFLAG_INFO); datalink_type = override_dlt; return 1; } // Blow up if we're not valid 802.11 headers // Need to not blow up on en10mb? Override. if (datalink_type == DLT_EN10MB) { snprintf(errstr, STATUS_MAX, "pcap reported netlink type 1 (EN10MB) for %s. " "This probably means you're not in RFMON mode or your drivers are " "reporting a bad value. Make sure you have the correct drivers " "and that entering monitor mode succeeded.", interface.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } else { snprintf(errstr, STATUS_MAX, "Unknown link type %d reported. Continuing on " "blindly and hoping we get something useful... Unless you have " "loaded plugins for this packet type, Kismet is not going to report " "useful packets.", datalink_type); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); } return 1; } int PacketSource_Pcap::FetchDescriptor() { if (pd == NULL) { return -1; } if (error) { return -1; } #ifdef HAVE_PCAP_GETSELFD return pcap_get_selectable_fd(pd); #else return -1; #endif } void PacketSource_Pcap::Pcap_Callback(u_char *bp, const struct pcap_pkthdr *header, const u_char *in_data) { // Copy into the globals memcpy(&callback_header, header, sizeof(pcap_pkthdr)); memcpy(callback_data, in_data, kismin(header->len, MAX_PACKET_LEN)); } int PacketSource_Pcap::Poll() { int ret; char errstr[STATUS_MAX] = ""; // Get data from the pcap callbacks if ((ret = pcap_dispatch(pd, 1, PacketSource_Pcap::Pcap_Callback, NULL)) < 0) { // If we failed to dispatch a packet collection, find out if the interface // got downed and give a smarter error message #ifdef SYS_LINUX int flags = 0; ret = Ifconfig_Get_Flags(interface.c_str(), errstr, &flags); if (ret >= 0 && (flags & IFF_UP) == 0) { snprintf(errstr, STATUS_MAX, "Failed to read a packet from %s. The " "interface is no longer up. Usually this happens when a DHCP " "client daemon is left running and times out, turning off the " "interface. See the Kismet README troubleshooting section " "for more information.", interface.c_str()); } else { #endif snprintf(errstr, STATUS_MAX, "Reading packet from pcap interface %s " "failed, interface is no longer available.", interface.c_str()); #ifdef SYS_LINUX } #endif error = 1; globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); CloseSource(); return 0; } if (ret == 0) return 0; if (paused) return 0; // Genesis a new packet, fill it in with the radio layer info if we have it, // and inject it into the system kis_packet *newpack = globalreg->packetchain->GeneratePacket(); // Get the timestamp from the pcap callback newpack->ts.tv_sec = callback_header.ts.tv_sec; newpack->ts.tv_usec = callback_header.ts.tv_usec; // Add the link-layer raw data to the packet, for the pristine copy kis_datachunk *linkchunk = new kis_datachunk; linkchunk->dlt = datalink_type; linkchunk->source_id = source_id; linkchunk->data = new uint8_t[kismin(callback_header.caplen, (uint32_t) MAX_PACKET_LEN)]; linkchunk->length = kismin(callback_header.caplen, (uint32_t) MAX_PACKET_LEN); memcpy(linkchunk->data, callback_data, linkchunk->length); newpack->insert(_PCM(PACK_COMP_LINKFRAME), linkchunk); // Only decode the DLT if we're asked to if (dlt_mangle) ManglePacket(newpack, linkchunk); num_packets++; // Flag the header kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = this; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); // Inject it into the packetchain globalreg->packetchain->ProcessPacket(newpack); // Packetchain destroys the packet at the end of processing, so we're done // with it here return 1; } int PacketSource_Pcap::ManglePacket(kis_packet *packet, kis_datachunk *linkchunk) { int ret = 0; if (linkchunk->dlt == DLT_PRISM_HEADER || linkchunk->dlt == DLT_IEEE802_11_RADIO_AVS) { ret = Prism2KisPack(packet, linkchunk); } else if (linkchunk->dlt == DLT_IEEE802_11_RADIO) { ret = Radiotap2KisPack(packet, linkchunk); } else if (linkchunk->dlt == DLT_PPI) { ret = PPI2KisPack(packet, linkchunk); } else if (linkchunk->dlt == DLT_IEEE802_11) { ret = Eight2KisPack(packet, linkchunk); } // We don't have to do anything else now other than add the signal headers. // If the packet only has a LINKFRAME then we can try to use it in place of // an 80211FRAME elsewhere in the packet decoders (note to self and others: // packet decoders need to process LINKFRAME if no 80211FRAME) if (ret < 0) { return ret; } // Pull the radio data FetchRadioData(packet); return ret; } int PacketSource_Pcap::Eight2KisPack(kis_packet *packet, kis_datachunk *linkchunk) { kis_datachunk *eight11chunk = NULL; eight11chunk = new kis_datachunk; eight11chunk->dlt = KDLT_IEEE802_11; eight11chunk->length = kismin((linkchunk->length - fcsbytes), (uint32_t) MAX_PACKET_LEN); eight11chunk->data = new uint8_t[eight11chunk->length]; memcpy(eight11chunk->data, linkchunk->data, eight11chunk->length); kis_fcs_bytes *fcschunk = NULL; if (fcsbytes && linkchunk->length > 4) { fcschunk = new kis_fcs_bytes; memcpy(fcschunk->fcs, &(linkchunk->data[linkchunk->length - 4]), 4); // Valid until proven otherwise fcschunk->fcsvalid = 1; packet->insert(_PCM(PACK_COMP_FCSBYTES), fcschunk); } // If we're validating the FCS if (validate_fcs && fcschunk != NULL) { // Compare it and flag the packet uint32_t calc_crc = crc32_le_80211(globalreg->crc32_table, eight11chunk->data, eight11chunk->length); if (memcmp(fcschunk->fcsp, &calc_crc, 4)) { packet->error = 1; fcschunk->fcsvalid = 0; //fprintf(stderr, "debug - dot11 to kis, fcs invalid\n"); } else { fcschunk->fcsvalid = 1; } } packet->insert(_PCM(PACK_COMP_80211FRAME), eight11chunk); return 1; } int PacketSource_Pcap::Prism2KisPack(kis_packet *packet, kis_datachunk *linkchunk) { int callback_offset = 0; char errstr[STATUS_MAX] = ""; // Make a datachunk for the reformatted frame kis_datachunk *eight11chunk = NULL; kis_layer1_packinfo *radioheader = NULL; // See if we have an AVS wlan header... avs_80211_1_header *v1hdr = (avs_80211_1_header *) linkchunk->data; if (linkchunk->length >= sizeof(avs_80211_1_header) && ntohl(v1hdr->version) == 0x80211001) { if (ntohl(v1hdr->length) > linkchunk->length || linkchunk->length < (ntohl(v1hdr->length) + fcsbytes)) { snprintf(errstr, STATUS_MAX, "pcap prism2 converter got corrupted " "AVS header length"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } eight11chunk = new kis_datachunk; radioheader = new kis_layer1_packinfo; eight11chunk->dlt = KDLT_IEEE802_11; // Subtract the packet FCS since kismet doesn't do anything terribly bright // with it right now, also subtract the avs header. We have to obey the // header length here since avs could change eight11chunk->length = kismin((linkchunk->length - ntohl(v1hdr->length) - fcsbytes), (uint32_t) MAX_PACKET_LEN); callback_offset = ntohl(v1hdr->length); // We REALLY need to do something smarter about this and handle the RSSI // type instead of just copying radioheader->signal_rssi = ntohl(v1hdr->ssi_signal); radioheader->noise_rssi = ntohl(v1hdr->ssi_noise); radioheader->freq_mhz = ChanToFreq(ntohl(v1hdr->channel)); switch (ntohl(v1hdr->phytype)) { case 1: radioheader->carrier = carrier_80211fhss; break; case 2: radioheader->carrier = carrier_80211dsss; break; case 4: case 5: radioheader->carrier = carrier_80211b; break; case 6: case 7: radioheader->carrier = carrier_80211g; break; case 8: radioheader->carrier = carrier_80211a; break; default: radioheader->carrier = carrier_unknown; break; } radioheader->encoding = (phy_encoding_type) ntohl(v1hdr->encoding); radioheader->datarate = (int) ntohl(v1hdr->datarate); } // See if we have a prism2 header wlan_ng_prism2_header *p2head = (wlan_ng_prism2_header *) linkchunk->data; if (linkchunk->length >= (sizeof(wlan_ng_prism2_header) + fcsbytes) && radioheader == NULL) { eight11chunk = new kis_datachunk; radioheader = new kis_layer1_packinfo; eight11chunk->dlt = KDLT_IEEE802_11; #if 0 // Subtract the packet FCS since kismet doesn't do anything terribly bright // with it right now if (p2head->frmlen.data < fcsbytes) { snprintf(errstr, STATUS_MAX, "pcap prism2 converter got corrupted " "wlanng-header frame length"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } #endif // We don't pay attention to the length provided by prism2hdr, since // some drivers get it wrong eight11chunk->length = kismin((linkchunk->length - sizeof(wlan_ng_prism2_header) - fcsbytes), (uint32_t) MAX_PACKET_LEN); #if 0 eight11chunk->length = kismin((p2head->frmlen.data - fcsbytes), (uint32_t) MAX_PACKET_LEN); #endif // Set our offset for extracting the actual data callback_offset = sizeof(wlan_ng_prism2_header); radioheader->signal_rssi = p2head->signal.data; radioheader->noise_rssi = p2head->noise.data; radioheader->freq_mhz = ChanToFreq(p2head->channel.data); } if (radioheader == NULL) { snprintf(errstr, STATUS_MAX, "pcap prism2 converter saw strange " "capture frame (PRISM80211 linktype, unable to determine " "prism headers)"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } eight11chunk->data = new uint8_t[eight11chunk->length]; memcpy(eight11chunk->data, linkchunk->data + callback_offset, eight11chunk->length); packet->insert(_PCM(PACK_COMP_RADIODATA), radioheader); packet->insert(_PCM(PACK_COMP_80211FRAME), eight11chunk); kis_fcs_bytes *fcschunk = NULL; if (fcsbytes && linkchunk->length > 4) { fcschunk = new kis_fcs_bytes; memcpy(fcschunk->fcs, &(linkchunk->data[linkchunk->length - 4]), 4); // Valid until proven otherwise fcschunk->fcsvalid = 1; packet->insert(_PCM(PACK_COMP_FCSBYTES), fcschunk); } // If we're validating the FCS if (validate_fcs && fcschunk != NULL) { // Compare it and flag the packet uint32_t calc_crc = crc32_le_80211(globalreg->crc32_table, eight11chunk->data, eight11chunk->length); if (memcmp(fcschunk->fcsp, &calc_crc, 4)) { packet->error = 1; fcschunk->fcsvalid = 0; } else { fcschunk->fcsvalid = 1; } } return 1; } /* * Convert MHz frequency to IEEE channel number. */ #if 0 static u_int ieee80211_mhz2ieee(u_int freq, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; if (freq < 5000) return 15 + ((freq - 2512) / 20); return (freq - 5000) / 5; } } #endif #define ALIGN_OFFSET(offset, width) \ ( (((offset) + ((width) - 1)) & (~((width) - 1))) - offset ) /* * Useful combinations of channel characteristics. */ #define IEEE80211_CHAN_FHSS \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) #define IEEE80211_CHAN_A \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_BPLUS \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK | IEEE80211_CHAN_TURBO) #define IEEE80211_CHAN_B \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) #define IEEE80211_CHAN_PUREG \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_G \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) #define IEEE80211_CHAN_T \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) #define IEEE80211_IS_CHAN_FHSS(_flags) \ ((_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) #define IEEE80211_IS_CHAN_A(_flags) \ ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) #define IEEE80211_IS_CHAN_BPLUS(_flags) \ ((_flags & IEEE80211_CHAN_BPLUS) == IEEE80211_CHAN_BPLUS) #define IEEE80211_IS_CHAN_B(_flags) \ ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) #define IEEE80211_IS_CHAN_PUREG(_flags) \ ((_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) #define IEEE80211_IS_CHAN_G(_flags) \ ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) #define IEEE80211_IS_CHAN_T(_flags) \ ((_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T) #define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x))) #define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x))) #define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x))) #define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x))) #define BITNO_2(x) (((x) & 2) ? 1 : 0) #define BIT(n) (1 << n) int PacketSource_Pcap::Radiotap2KisPack(kis_packet *packet, kis_datachunk *linkchunk) { union { int8_t i8; int16_t i16; u_int8_t u8; u_int16_t u16; u_int32_t u32; u_int64_t u64; } u; union { int8_t i8; int16_t i16; u_int8_t u8; u_int16_t u16; u_int32_t u32; u_int64_t u64; } u2; struct ieee80211_radiotap_header *hdr; u_int32_t present, next_present; u_int32_t *presentp, *last_presentp; enum ieee80211_radiotap_type bit; const u_char *iter_start; unsigned int iter_align; int bit0; const u_char *iter; int fcs_cut = 0; // Is the FCS bit set? char errstr[STATUS_MAX]; u.u64 = u2.u64 = 0; kis_datachunk *eight11chunk = NULL; kis_layer1_packinfo *radioheader = NULL; if (linkchunk->length < sizeof(*hdr)) { snprintf(errstr, STATUS_MAX, "pcap radiotap converter got corrupted " "Radiotap header length"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } // Assign it to the callback data hdr = (struct ieee80211_radiotap_header *) linkchunk->data; if (linkchunk->length < EXTRACT_LE_16BITS(&hdr->it_len)) { snprintf(errstr, STATUS_MAX, "pcap radiotap converter got corrupted " "Radiotap header length"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } // null-statement for-loop for (last_presentp = &hdr->it_present; (EXTRACT_LE_32BITS(last_presentp) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 && (u_char *) (last_presentp + 1) <= linkchunk->data + EXTRACT_LE_16BITS(&(hdr->it_len)); last_presentp++); /* are there more bitmap extensions than bytes in header? */ if ((EXTRACT_LE_32BITS(last_presentp) & BIT(IEEE80211_RADIOTAP_EXT)) != 0) { snprintf(errstr, STATUS_MAX, "pcap radiotap converter got corrupted " "Radiotap bitmap length"); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } eight11chunk = new kis_datachunk; radioheader = new kis_layer1_packinfo; eight11chunk->dlt = KDLT_IEEE802_11; // iter = (u_char*)(last_presentp + 1); iter_start = iter = (u_char*)(last_presentp + 1); for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp; presentp++, bit0 += 32) { for (present = EXTRACT_LE_32BITS(presentp); present; present = next_present) { /* clear the least significant bit that is set */ next_present = present & (present - 1); /* extract the least significant bit that is set */ bit = (enum ieee80211_radiotap_type) (bit0 + BITNO_32(present ^ next_present)); switch (bit) { case IEEE80211_RADIOTAP_FLAGS: case IEEE80211_RADIOTAP_RATE: /* case IEEE80211_RADIOTAP_DB_ANTSIGNAL: case IEEE80211_RADIOTAP_DB_ANTNOISE: */ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: case IEEE80211_RADIOTAP_DBM_ANTNOISE: case IEEE80211_RADIOTAP_ANTENNA: u.u8 = *iter++; break; case IEEE80211_RADIOTAP_DBM_TX_POWER: u.i8 = *iter++; break; case IEEE80211_RADIOTAP_CHANNEL: iter_align = ALIGN_OFFSET((unsigned int) (iter - iter_start), 2); iter += iter_align; u.u16 = EXTRACT_LE_16BITS(iter); iter += sizeof(u.u16); u2.u16 = EXTRACT_LE_16BITS(iter); iter += sizeof(u2.u16); break; case IEEE80211_RADIOTAP_FHSS: case IEEE80211_RADIOTAP_LOCK_QUALITY: case IEEE80211_RADIOTAP_TX_ATTENUATION: case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: iter_align = ALIGN_OFFSET((unsigned int) (iter - iter_start), 2); iter += iter_align; u.u16 = EXTRACT_LE_16BITS(iter); iter += sizeof(u.u16); break; case IEEE80211_RADIOTAP_TSFT: iter_align = ALIGN_OFFSET((unsigned int) (iter - iter_start), 8); iter += iter_align; u.u64 = EXTRACT_LE_64BITS(iter); iter += sizeof(u.u64); break; #if defined(SYS_OPENBSD) case IEEE80211_RADIOTAP_RSSI: u.u8 = EXTRACT_LE_8BITS(iter); iter += sizeof(u.u8); u2.u8 = EXTRACT_LE_8BITS(iter); iter += sizeof(u2.u8); break; #endif default: /* this bit indicates a field whose * size we do not know, so we cannot * proceed. */ next_present = 0; continue; } switch (bit) { case IEEE80211_RADIOTAP_CHANNEL: // radioheader->channel = ieee80211_mhz2ieee(u.u16, u2.u16); radioheader->freq_mhz = u.u16; if (IEEE80211_IS_CHAN_FHSS(u2.u16)) radioheader->carrier = carrier_80211fhss; else if (IEEE80211_IS_CHAN_A(u2.u16)) radioheader->carrier = carrier_80211a; else if (IEEE80211_IS_CHAN_BPLUS(u2.u16)) radioheader->carrier = carrier_80211bplus; else if (IEEE80211_IS_CHAN_B(u2.u16)) radioheader->carrier = carrier_80211b; else if (IEEE80211_IS_CHAN_PUREG(u2.u16)) radioheader->carrier = carrier_80211g; else if (IEEE80211_IS_CHAN_G(u2.u16)) radioheader->carrier = carrier_80211g; else if (IEEE80211_IS_CHAN_T(u2.u16)) radioheader->carrier = carrier_80211a;/*XXX*/ else radioheader->carrier = carrier_unknown; if ((u2.u16 & IEEE80211_CHAN_CCK) == IEEE80211_CHAN_CCK) radioheader->encoding = encoding_cck; else if ((u2.u16 & IEEE80211_CHAN_OFDM) == IEEE80211_CHAN_OFDM) radioheader->encoding = encoding_ofdm; else if ((u2.u16 & IEEE80211_CHAN_DYN) == IEEE80211_CHAN_DYN) radioheader->encoding = encoding_dynamiccck; else if ((u2.u16 & IEEE80211_CHAN_GFSK) == IEEE80211_CHAN_GFSK) radioheader->encoding = encoding_gfsk; else radioheader->encoding = encoding_unknown; break; case IEEE80211_RADIOTAP_RATE: /* strip basic rate bit & convert to kismet units */ radioheader->datarate = ((u.u8 &~ 0x80) / 2) * 10; break; /* ignore DB values, they're not helpful case IEEE80211_RADIOTAP_DB_ANTSIGNAL: radioheader->signal_dbm = u.i8; break; case IEEE80211_RADIOTAP_DB_ANTNOISE: radioheader->noise_dbm = u.i8; break; */ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: radioheader->signal_dbm = u.i8; break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: radioheader->noise_dbm = u.i8; break; case IEEE80211_RADIOTAP_FLAGS: if (u.u8 & IEEE80211_RADIOTAP_F_FCS) { fcs_cut = 4; } break; #if defined(SYS_OPENBSD) case IEEE80211_RADIOTAP_RSSI: /* Convert to Kismet units... No reason to use RSSI units * here since we know the conversion factor */ radioheader->signal_dbm = int((float(u.u8) / float(u2.u8) * 255)); break; #endif default: break; } } } if (EXTRACT_LE_16BITS(&(hdr->it_len)) + fcs_cut > (int) linkchunk->length) { /* _MSG("Pcap Radiotap converter got corrupted Radiotap frame, not " "long enough for radiotap header plus indicated FCS", MSGFLAG_ERROR); */ delete eight11chunk; delete radioheader; return 0; } eight11chunk->length = linkchunk->length - EXTRACT_LE_16BITS(&(hdr->it_len)) - fcs_cut; eight11chunk->data = new uint8_t[eight11chunk->length]; memcpy(eight11chunk->data, linkchunk->data + EXTRACT_LE_16BITS(&(hdr->it_len)), eight11chunk->length); packet->insert(_PCM(PACK_COMP_RADIODATA), radioheader); packet->insert(_PCM(PACK_COMP_80211FRAME), eight11chunk); kis_fcs_bytes *fcschunk = NULL; if (fcs_cut && linkchunk->length > 4) { fcschunk = new kis_fcs_bytes; memcpy(fcschunk->fcs, &(linkchunk->data[linkchunk->length - 4]), 4); // Valid until proven otherwise fcschunk->fcsvalid = 1; packet->insert(_PCM(PACK_COMP_FCSBYTES), fcschunk); } // If we're validating the FCS if (validate_fcs && fcschunk != NULL) { // Compare it and flag the packet uint32_t calc_crc = crc32_le_80211(globalreg->crc32_table, eight11chunk->data, eight11chunk->length); if (memcmp(fcschunk->fcsp, &calc_crc, 4)) { packet->error = 1; fcschunk->fcsvalid = 0; // fprintf(stderr, "debug - rtap to kis, fcs invalid\n"); } else { fcschunk->fcsvalid = 1; } } return 1; } #undef BITNO_32 #undef BITNO_16 #undef BITNO_8 #undef BITNO_4 #undef BITNO_2 #undef BIT int PacketSource_Pcap::PPI2KisPack(kis_packet *packet, kis_datachunk *linkchunk) { ppi_packet_header *ppi_ph; ppi_field_header *ppi_fh; unsigned int ppi_fh_offt = sizeof(ppi_packet_header); unsigned int tuint, ph_len; int applyfcs = 0, fcsknownbad = 0; // Make a datachunk for the reformatted frame kis_datachunk *eight11chunk = NULL; kis_layer1_packinfo *radioheader = NULL; kis_gps_packinfo *gpsinfo = NULL; if (linkchunk->length < sizeof(ppi_packet_header)) { _MSG("pcap PPI converter got runt PPI frame", MSGFLAG_ERROR); return 0; } ppi_ph = (ppi_packet_header *) linkchunk->data; ph_len = kis_letoh16(ppi_ph->pph_len); if (ph_len > linkchunk->length) { _MSG("pcap PPI converter got invalid/runt PPI frame header", MSGFLAG_ERROR); return 0; } // Fix broken kismet dumps where kismet logged the wrong size (always // size 24) - if we're size 24, we have a PPI 11n common header, and // we can fit it all, then we adjust the header size up if (ph_len == 24 && linkchunk->length > 32) { ppi_fh = (ppi_field_header *) &(linkchunk->data[ppi_fh_offt]); if (kis_letoh16(ppi_fh->pfh_datatype) == PPI_FIELD_11COMMON) ph_len = 32; } // Ignore the DLT and treat it all as 802.11... for now while (ppi_fh_offt < linkchunk->length && ppi_fh_offt < ph_len) { ppi_fh = (ppi_field_header *) &(linkchunk->data[ppi_fh_offt]); unsigned int fh_len = kis_letoh16(ppi_fh->pfh_datalen); unsigned int fh_type = kis_letoh16(ppi_fh->pfh_datatype); if (fh_len > linkchunk->length || fh_len > ph_len) { _MSG("pcap PPI converter got corrupt/invalid PPI field length", MSGFLAG_ERROR); return 0; } ppi_fh_offt += fh_len + sizeof(ppi_field_header); if (fh_type == PPI_FIELD_11COMMON) { // printf("debug - 80211 common\n"); ppi_80211_common *ppic = (ppi_80211_common *) ppi_fh; // Common flags tuint = kis_letoh16(ppic->flags); if ((tuint & PPI_80211_FLAG_INVALFCS) || (tuint & PPI_80211_FLAG_PHYERROR)) { // Junk packets that are FCS or phy compromised return 0; } if (tuint & PPI_80211_FLAG_FCS) { applyfcs = 1; } if ((tuint & PPI_80211_FLAG_FCS) && (tuint & PPI_80211_FLAG_INVALFCS)) { applyfcs = 1; fcsknownbad = 1; } if (radioheader == NULL) radioheader = new kis_layer1_packinfo; // Channel flags tuint = kis_letoh16(ppic->chan_flags); if (tuint & PPI_80211_CHFLAG_CCK) radioheader->encoding = encoding_cck; if (tuint & PPI_80211_CHFLAG_OFDM) radioheader->encoding = encoding_ofdm; if (tuint & PPI_80211_CHFLAG_DYNAMICCCK) radioheader->encoding = encoding_dynamiccck; if (tuint & PPI_80211_CHFLAG_GFSK) radioheader->encoding = encoding_gfsk; if (tuint & PPI_80211_CHFLAG_TURBO) radioheader->carrier = carrier_80211bplus; if ((tuint & PPI_80211_CHFLAG_OFDM) && (tuint & PPI_80211_CHFLAG_2GHZ)) radioheader->carrier = carrier_80211g; if (tuint & PPI_80211_CHFLAG_5GHZ) radioheader->carrier = carrier_80211a; radioheader->signal_dbm = ppic->signal_dbm; radioheader->noise_dbm = ppic->noise_dbm; radioheader->datarate = kis_letoh16(ppic->rate) * 5; radioheader->freq_mhz = kis_letoh16(ppic->freq_mhz); } else if (fh_type == PPI_FIELD_11NMAC) { ppi_11n_mac *ppin = (ppi_11n_mac *) ppi_fh; if (radioheader == NULL) radioheader = new kis_layer1_packinfo; // Decode greenfield notation tuint = kis_letoh16(ppin->flags); if (tuint & PPI_11NMAC_HT2040) radioheader->carrier = carrier_80211n20; else radioheader->carrier = carrier_80211n40; } else if (fh_type == PPI_FIELD_11NMACPHY) { ppi_11n_macphy *ppinp = (ppi_11n_macphy *) ppi_fh; if (radioheader == NULL) radioheader = new kis_layer1_packinfo; // Decode greenfield notation tuint = kis_letoh16(ppinp->flags); if (tuint & PPI_11NMAC_HT2040) radioheader->carrier = carrier_80211n20; else radioheader->carrier = carrier_80211n40; } else if (fh_type == PPI_FIELD_GPS) { ppi_gps_hdr *ppigps = (ppi_gps_hdr *) ppi_fh; if (ppigps->version == 0) { unsigned int data_offt = 0; uint32_t fields_present = kis_letoh32(ppigps->fields_present); uint16_t gps_len = kis_letoh16(ppigps->gps_len) - sizeof(ppi_gps_hdr); union block { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; } *u; // printf("debug - gps present, %u len %d %d %d %d\n", fields_present, gps_len, fields_present & PPI_GPS_FLAG_LAT, fields_present & PPI_GPS_FLAG_LON, fields_present & PPI_GPS_FLAG_ALT); if ((fields_present & PPI_GPS_FLAG_LAT) && (fields_present & PPI_GPS_FLAG_LON) && gps_len - data_offt >= 8) { if (gpsinfo == NULL) gpsinfo = new kis_gps_packinfo; u = (block *) &(ppigps->field_data[data_offt]); gpsinfo->lat = fixed3_7_to_double(kis_letoh32(u->u32)); data_offt += 4; u = (block *) &(ppigps->field_data[data_offt]); gpsinfo->lon = fixed3_7_to_double(kis_letoh32(u->u32)); data_offt += 4; gpsinfo->gps_fix = 2; gpsinfo->alt = 0; } //Speed is stored as a velocity in VECTOR tags.. /* if ((fields_present & PPI_GPS_FLAG_SPD) && gps_len - data_offt >= 4) { u = (block *) &(ppigps->field_data[data_offt]); gpsinfo->spd = fixed3_7_to_double(kis_letoh32(u->u32)); data_offt += 4; } */ if ((fields_present & PPI_GPS_FLAG_ALT) && gps_len - data_offt >= 4) { gpsinfo->gps_fix = 3; u = (block *) &(ppigps->field_data[data_offt]); gpsinfo->alt = fixed6_4_to_double(kis_letoh32(u->u32)); data_offt += 4; } packet->insert(_PCM(PACK_COMP_GPS), gpsinfo); } } } if (applyfcs) applyfcs = 4; eight11chunk = new kis_datachunk; eight11chunk->dlt = KDLT_IEEE802_11; // Subtract the packet FCS since kismet doesn't do anything terribly bright // with it right now, also subtract the avs header. We have to obey the // header length here since avs could change eight11chunk->length = kismin((linkchunk->length - ph_len - applyfcs), (uint32_t) MAX_PACKET_LEN); eight11chunk->data = new uint8_t[eight11chunk->length]; memcpy(eight11chunk->data, linkchunk->data + ph_len, eight11chunk->length); if (radioheader != NULL) packet->insert(_PCM(PACK_COMP_RADIODATA), radioheader); packet->insert(_PCM(PACK_COMP_80211FRAME), eight11chunk); kis_fcs_bytes *fcschunk = NULL; if (applyfcs && linkchunk->length > 4) { fcschunk = new kis_fcs_bytes; memcpy(fcschunk->fcs, &(linkchunk->data[linkchunk->length - 4]), 4); // Listen to the PPI file for known bad, regardless if we have validate // turned on or not if (fcsknownbad) fcschunk->fcsvalid = 0; else fcschunk->fcsvalid = 1; packet->insert(_PCM(PACK_COMP_FCSBYTES), fcschunk); } // If we're validating the FCS if (validate_fcs && fcschunk != NULL) { // Compare it and flag the packet uint32_t calc_crc = crc32_le_80211(globalreg->crc32_table, eight11chunk->data, eight11chunk->length); if (memcmp(fcschunk->fcsp, &calc_crc, 4)) { packet->error = 1; fcschunk->fcsvalid = 0; fprintf(stderr, "debug - rtap to kis, fcs invalid\n"); } else { fcschunk->fcsvalid = 1; } } return 1; } int PacketSource_Pcap::FetchHardwareChannel() { return 0; } int PacketSource_Pcapfile::AutotypeProbe(string in_device) { // Autodetect as a pcapfile if it's a regular file in the fs struct stat sbuf; if (stat(in_device.c_str(), &sbuf) < 0) return 0; if (S_ISREG(sbuf.st_mode)) { type = "pcapfile"; return 1; } return 0; } int PacketSource_Pcapfile::RegisterSources(Packetsourcetracker *tracker) { // Register the pcapfile source based off ourselves, nonroot, no channels tracker->RegisterPacketProto("pcapfile", this, "n/a", 0); return 1; } int PacketSource_Pcapfile::OpenSource() { last_channel = 0; char errstr[STATUS_MAX] = ""; // Open the file offline and bounce out the error pd = pcap_open_offline(interface.c_str(), errstr); if (strlen(errstr) > 0) { globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } paused = 0; num_packets = 0; if (DatalinkType() < 0) return -1; genericparms.weak_dissect = 1; return 1; } int PacketSource_Pcapfile::Poll() { int ret; ret = pcap_dispatch(pd, 1, PacketSource_Pcapfile::Pcap_Callback, NULL); if (ret < 0) { globalreg->messagebus->InjectMessage("Pcap failed to get the next packet", MSGFLAG_ERROR); return 0; } else if (ret == 0) { globalreg->messagebus->InjectMessage("Pcap file reached end of capture", MSGFLAG_ERROR); CloseSource(); return 0; } if (paused) return 0; kis_packet *newpack = globalreg->packetchain->GeneratePacket(); // Get the timestamp from the pcap callback newpack->ts.tv_sec = callback_header.ts.tv_sec; newpack->ts.tv_usec = callback_header.ts.tv_usec; // Add the link-layer raw data to the packet, for the pristine copy kis_datachunk *linkchunk = new kis_datachunk; linkchunk->dlt = datalink_type; linkchunk->source_id = source_id; linkchunk->data = new uint8_t[kismin(callback_header.caplen, (uint32_t) MAX_PACKET_LEN)]; linkchunk->length = kismin(callback_header.caplen, (uint32_t) MAX_PACKET_LEN); memcpy(linkchunk->data, callback_data, linkchunk->length); newpack->insert(_PCM(PACK_COMP_LINKFRAME), linkchunk); // Only decode the DLT if we're asked to if (dlt_mangle && ManglePacket(newpack, linkchunk) < 0) return 0; num_packets++; // Flag the header kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = this; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); globalreg->packetchain->ProcessPacket(newpack); return 1; } #endif kismet-2013-03-R1b/extra/0000775000175000017500000000000012124602454014576 5ustar dragorndragornkismet-2013-03-R1b/extra/kismet-3.1.0.dtd0000664000175000017500000002466012124602454017234 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-1.6.1.dtd0000664000175000017500000002405612124602454017237 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-1.6.2.dtd0000664000175000017500000002430212124602454017232 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-gps-1.0.dtd0000664000175000017500000001636412124602454017664 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-1.4.dtd0000664000175000017500000002152112124602454017070 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-1.6.dtd0000664000175000017500000002401512124602454017073 0ustar dragorndragorn kismet-2013-03-R1b/extra/Makefile.in0000664000175000017500000000167112124602454016650 0ustar dragorndragornHOME = @srcdir@ CXX = @CXX@ CC = @CC@ LD = @CXX@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ CFLAGS = @CPPFLAGS@ CXXFLAGS = -Wall @CXXFLAGS@ CPPFLAGS = @CPPFLAGS@ -I../ SUID = @suid@ prefix = @prefix@ exec_prefix = @exec_prefix@ ETC = @sysconfdir@ BIN = @bindir@ SHARE = @datadir@/kismet/ WAV = ${SHARE}/wav/ CWGDO = kismet2cwgd.o ../expat.o CWGD = kismet2cwgd XMLO = kismet2xml.o XML = kismet2xml SANITO = ../gpsmap_samples.o ../expat.o gpsxml-sanitize.o SANIT = gpsxml-sanitize all: $(XML) $(CWGD): $(CWGDO) $(LD) $(LDFLAGS) -o $(CWGD) $(CWGDO) $(LIBS) -lexpat $(XML): $(XMLO) $(LD) $(LDFLAGS) -o $(XML) $(XMLO) $(LIBS) $(SANIT): $(SANITO) $(LD) $(LDFLAGS) -o $(SANIT) $(SANITO) $(LIBS) -lexpat -lz clean: @-rm -f *.o @-rm -f $(CWGD) @-rm -f $(XML) distclean: @-make clean @-rm -f *~ @-rm -f Makefile .c.o: $(DEPEND) $(CC) $(CFLAGS) -c $*.c -o $@ .cc.o: $(DEPEND) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/extra/kismet-1.3.dtd0000664000175000017500000002147112124602454017073 0ustar dragorndragorn kismet-2013-03-R1b/extra/old/0000775000175000017500000000000012124602454015354 5ustar dragorndragornkismet-2013-03-R1b/extra/old/listchan.pl0000775000175000017500000000051612124602454017523 0ustar dragorndragorn#!/usr/bin/perl $device = shift; die("No device specified") if ($device eq ""); for ($i = 0; $i < 255; $i++) { undef $bad; open (IWCONFIG, "iwconfig 2>&1 $device channel $i|"); while () { /Error for wireless request "Set Frequency"/ && ($bad++); } next if $bad; $list .= "$i,"; } $list =~ s/,$//; print "$list\n"; kismet-2013-03-R1b/extra/old/gpsdrive-1.32-heading.patch0000664000175000017500000000502612124602454022201 0ustar dragorndragorndiff -ur gpsdrive-1.32/src/gpsd.c gpsdrive-1.32-heading/src/gpsd.c --- gpsdrive-1.32/src/gpsd.c 2003-01-23 06:05:34.000000000 -0800 +++ gpsdrive-1.32-heading/src/gpsd.c 2003-07-21 11:47:53.000000000 -0700 @@ -663,6 +663,10 @@ sprintf (reply + strlen (reply), ",R=1"); } break; + case 'H': + case 'h': + sprintf (reply + strlen (reply), ",H=%.5f", gNMEAdata.heading); + break; case 'S': case 's': sprintf (reply + strlen (reply), ",S=%d", gNMEAdata.status); diff -ur gpsdrive-1.32/src/nmea.h gpsdrive-1.32-heading/src/nmea.h --- gpsdrive-1.32/src/nmea.h 2002-09-25 03:04:52.000000000 -0700 +++ gpsdrive-1.32-heading/src/nmea.h 2003-07-18 19:52:25.000000000 -0700 @@ -4,6 +4,7 @@ #define GPGSA "GPGSA" #define GPGSV "GPGSV" #define GPRMC "GPRMC" +#define HCHDG "HCHDG" #define PRWIZCH "PRWIZCH" struct OUTDATA { @@ -76,6 +77,8 @@ int seen[12]; int valid[12]; /* signal valid */ + + double heading; }; #define C_LATLON 1 @@ -84,6 +87,7 @@ /* prototypes */ extern void doNMEA(short refNum); +extern void processHCHDG(char *sentence); extern void processGPRMC(char *sentence); extern void processGPGGA(char *sentence); extern void processGPGSV(char *sentence); diff -ur gpsdrive-1.32/src/nmea_parse.c gpsdrive-1.32-heading/src/nmea_parse.c --- gpsdrive-1.32/src/nmea_parse.c 2002-09-25 03:04:52.000000000 -0700 +++ gpsdrive-1.32-heading/src/nmea_parse.c 2003-07-19 14:27:19.000000000 -0700 @@ -14,6 +14,25 @@ #endif /* ----------------------------------------------------------------------- */ + +/* HCHDG format: + * $HCHDG,heading,,,deviation + * sentence = 'HCHDG,51.8,,,13.0,E*27' + */ +void processHCHDG(char *sentence) { + int i, rv; + double heading; + + rv = sscanf( field( sentence, 1 ), "%lg", &heading ); + if( rv != 1 ) { + return; /* don't set anything */ + } + + gNMEAdata.heading = heading; + + return; +} + /* The time field in the GPRMC sentence is in the format hhmmss; the date field is in the format ddmmyy. The output will diff -ur gpsdrive-1.32/src/tm.c gpsdrive-1.32-heading/src/tm.c --- gpsdrive-1.32/src/tm.c 2002-06-28 17:23:18.000000000 -0700 +++ gpsdrive-1.32-heading/src/tm.c 2003-07-19 14:08:25.000000000 -0700 @@ -27,6 +27,8 @@ if (checksum(sentence)) { if (strncmp(GPRMC, sentence, 5) == 0) { processGPRMC(sentence); + } else if (strncmp(HCHDG, sentence, 5) == 0) { + processHCHDG(sentence); } else if (strncmp(GPGGA, sentence, 5) == 0) { processGPGGA(sentence); } else if (strncmp(GPGSA, sentence, 5) == 0) { kismet-2013-03-R1b/extra/old/manuf_update.sh0000775000175000017500000000022212124602454020357 0ustar dragorndragorn#!/bin/bash wget http://www.unbolted.net/dump_clients.php -O ../conf/client_manuf wget http://www.unbolted.net/dump_aps.php -O ../conf/ap_manuf kismet-2013-03-R1b/extra/old/ieee-manuf-tr.sh0000775000175000017500000000031712124602454020352 0ustar dragorndragorn#!/bin/sh # translate data from # to kismet format sed -n 's,^\(..\)-\(..\)-\(..\)[ ]*(hex)[ ]*\(.*\)$,\1:\2:\3:00:00:00/FF:FF:FF:00:00:00 \4 Unknown 0,p' kismet-2013-03-R1b/extra/old/kismet2xml.cc0000664000175000017500000003255412124602454017773 0ustar dragorndragorn#include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include #include "getopt.h" #include #include #include #include #include #include #include #include "gpsdump.h" #define GPS_VERSION 5 // Lets just pretend v3 never existed. // Sacred cows make the best hamburger. #ifndef WORDS_BIGENDIAN // Little endian magic #define GPS_MAGIC 0xDEADBEEF #else // Big endian magic #define GPS_MAGIC 0xEFEBADDE #endif // Number of networks in the header #define HEADER_NUM 4096 // Offset of the data segment #define DATA_OFFSET (sizeof(GPSDump::file_hdr) + (sizeof(GPSDump::net_hdr) * HEADER_NUM)) // Defines of the old binary formats typedef struct { int32_t tv_sec; int32_t tv_usec; } time_hdr; typedef struct { uint32_t magic; uint8_t version; time_hdr start; } file_hdr; typedef struct { uint16_t number; uint8_t bssid[6]; uint8_t ssid[SSID_SIZE]; } net_hdr; typedef struct { uint16_t number; uint8_t bssid[6]; uint8_t ssid[SSID_SIZE]; } net_hdr_v3; typedef struct { uint8_t number; uint8_t bssid[6]; uint8_t ssid[SSID_SIZE]; } net_hdr_v2; typedef struct { uint8_t number; uint8_t bssid[6]; uint8_t ssid[SSID_SIZE]; } net_hdr_v1; typedef struct { uint16_t number; int16_t lat; int64_t lat_mant; int16_t lon; int64_t lon_mant; int16_t alt; int64_t alt_mant; int16_t spd; int64_t spd_mant; int16_t fix; uint16_t quality; uint16_t power; uint16_t noise; time_hdr ts; } data_pkt; typedef struct { uint8_t number; int16_t lat; int64_t lat_mant; int16_t lon; int64_t lon_mant; int16_t alt; int64_t alt_mant; int16_t spd; int64_t spd_mant; int16_t fix; uint16_t power; time_hdr ts; } data_pkt_v3; typedef struct { uint8_t number; int16_t lat; int64_t lat_mant; int16_t lon; int64_t lon_mant; int16_t alt; int64_t alt_mant; int16_t spd; int64_t spd_mant; int16_t fix; uint16_t power; time_hdr ts; } data_pkt_v2; typedef struct { uint8_t number; int16_t lat; int64_t lat_mant; int16_t lon; int64_t lon_mant; int16_t alt; int64_t alt_mant; int16_t spd; int64_t spd_mant; int16_t fix; time_hdr ts; } data_pkt_v1; typedef struct gps_network { net_hdr header; double max_lat; double min_lat; double max_lon; double min_lon; double max_alt; double min_alt; int count; double avg_lat, avg_lon, avg_alt, avg_spd; double diagonal_distance, altitude_distance; // Index to the netcolors table int color_index; }; string Mac2String(uint8_t *mac, char seperator) { char tempstr[MAC_STR_LEN]; // There must be a better way to do this... if (seperator != '\0') snprintf(tempstr, MAC_STR_LEN, "%02X%c%02X%c%02X%c%02X%c%02X%c%02X", mac[0], seperator, mac[1], seperator, mac[2], seperator, mac[3], seperator, mac[4], seperator, mac[5]); else snprintf(tempstr, MAC_STR_LEN, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); string temp = tempstr; return temp; } int ProcessGPSFile(char *in_fname, char *in_oname, char *in_netfname) { vector net_vec; #ifdef HAVE_LIBZ gzFile gpsfz; #else FILE *gpsf; #endif #ifdef HAVE_LIBZ if ((gpsfz = gzopen(in_fname, "rb")) == NULL) { #else if ((gpsf = fopen(in_fname, "rb")) == NULL) { #endif fprintf(stderr, "FATAL: Could not open data file.\n"); return -1; } FILE *outf; if (in_oname == NULL) { outf = stdout; } else { if ((outf = fopen(in_oname, "w")) == NULL) { fprintf(stderr, "FATAL: Could not open output file (%s) for appending\n", in_oname); return -1; } } file_hdr filhdr; /* if (fread(&filhdr, sizeof(file_hdr), 1, gpsf) < 1) { fprintf(stderr, "FATAL: Could not read header.\n"); return -1; } */ #ifdef HAVE_LIBZ if (gzread(gpsfz, &filhdr, sizeof(file_hdr)) < (int) sizeof(file_hdr)) #else if (fread(&filhdr, sizeof(file_hdr), 1, gpsf) < 1) #endif { fprintf(stderr, "FATAL: Could not read header.\n"); return -1; } if (filhdr.magic != GPS_MAGIC) { fprintf(stderr, "FATAL: Invalid gpsdump magic on %s.\n", in_fname); return -1; } if (filhdr.version > 4) { fprintf(stderr, "FATAL: Unsupported version %d.\n", filhdr.version); return -1; } net_hdr nethdr[HEADER_NUM]; memset(nethdr, 0, sizeof(net_hdr) * HEADER_NUM); // Yes this is a nasty repetition of code. // No I don't have a better way of doing it. if (filhdr.version == 1) { net_hdr_v1 nethdr_v1[254]; #ifdef HAVE_LIBZ if (gzread(gpsfz, &nethdr_v1, sizeof(net_hdr_v1) * 254) < (int) sizeof(net_hdr_v1) * 254) #else if (fread(&nethdr_v1, sizeof(net_hdr_v1), 254, gpsf) < 254) #endif { fprintf(stderr, "FATAL: Could not read network headers.\n"); return -1; } // These are easy since they didn't change but we'll read them seperately anyhow for (int x = 0; x < 254; x++) { /* typedef struct { uint8_t number; uint8_t bssid[6]; uint8_t ssid[SSID_SIZE]; } net_hdr; */ nethdr[x].number = nethdr_v1[x].number; memcpy(nethdr[x].bssid, nethdr_v1[x].bssid, 6); memcpy(nethdr[x].ssid, nethdr_v1[x].ssid, SSID_SIZE); } } else if (filhdr.version == 2) { net_hdr_v2 nethdr_v2[254]; #ifdef HAVE_LIBZ if (gzread(gpsfz, &nethdr_v2, sizeof(net_hdr_v2) * 254) < (int) sizeof(net_hdr_v2) * 254) #else if (fread(&nethdr_v2, sizeof(net_hdr_v2), 254, gpsf) < 254) #endif { fprintf(stderr, "FATAL: Could not read network headers.\n"); return -1; } // These are easy since they didn't change but we'll read them seperately anyhow for (int x = 0; x < 254; x++) { nethdr[x].number = nethdr_v2[x].number; memcpy(nethdr[x].bssid, nethdr_v2[x].bssid, 6); memcpy(nethdr[x].ssid, nethdr_v2[x].ssid, SSID_SIZE); } } else if (filhdr.version == 3) { net_hdr_v3 nethdr_v3[254]; #ifdef HAVE_LIBZ if (gzread(gpsfz, &nethdr_v3, sizeof(net_hdr_v3) * 254) < (int) sizeof(net_hdr_v3) * 254) #else if (fread(&nethdr_v3, sizeof(net_hdr_v3), 254, gpsf) < 254) #endif { fprintf(stderr, "FATAL: Could not read network headers.\n"); return -1; } // These are easy since they didn't change but we'll read them seperately anyhow for (int x = 0; x < 254; x++) { nethdr[x].number = nethdr_v3[x].number; memcpy(nethdr[x].bssid, nethdr_v3[x].bssid, 6); memcpy(nethdr[x].ssid, nethdr_v3[x].ssid, SSID_SIZE); } } else { #ifdef HAVE_LIBZ if (gzread(gpsfz, &nethdr, sizeof(net_hdr) * HEADER_NUM) < (int) sizeof(net_hdr) * HEADER_NUM) #else if (fread(&nethdr, sizeof(net_hdr), HEADER_NUM, gpsf) < HEADER_NUM) #endif { fprintf(stderr, "FATAL: Could not read network headers.\n"); return -1; } } for (int x = 0; x < HEADER_NUM; x++) { gps_network netw; // printf("Got header '%s'\n", nethdr[x].ssid); memset(&netw, 0, sizeof(gps_network)); netw.header = nethdr[x]; /* printf("got network header %d encode number %d '%s'\n", x, netw.header.number, netw.header.ssid); */ net_vec.push_back(netw); } data_pkt dpkt; data_pkt_v1 dpkt_v1; data_pkt_v2 dpkt_v2; int read_ret = 1; time_t file_start = filhdr.start.tv_sec; // Write the XML headers fprintf(outf, "\n\n\n"); fprintf(outf, "\n\n", GPS_VERSION, ctime(&file_start)); if (in_netfname != NULL) { fprintf(outf, " %s\n\n", in_netfname); } int file_samples = 0; while (read_ret > 0) { file_samples++; if (filhdr.version == 1) { #ifdef HAVE_LIBZ read_ret = gzread(gpsfz, &dpkt_v1, sizeof(dpkt_v1)); #else read_ret = fread(&dpkt_v1, sizeof(dpkt_v1), 1, gpsf); #endif dpkt.number = dpkt_v1.number; dpkt.lat = dpkt_v1.lat; dpkt.lat_mant = dpkt_v1.lat_mant; dpkt.lon = dpkt_v1.lon; dpkt.lon_mant = dpkt_v1.lon_mant; dpkt.alt = dpkt_v1.alt; dpkt.alt_mant = dpkt_v1.alt_mant; dpkt.spd = dpkt_v1.spd; dpkt.spd_mant = dpkt_v1.spd_mant; dpkt.fix = dpkt_v1.fix; dpkt.power = 0; memcpy(&dpkt.ts, &dpkt_v1.ts, sizeof(time_hdr)); } else if (filhdr.version == 2 || filhdr.version == 3) { #ifdef HAVE_LIBZ read_ret = gzread(gpsfz, &dpkt_v2, sizeof(dpkt_v2)); #else read_ret = fread(&dpkt_v2, sizeof(dpkt_v2), 1, gpsf); #endif dpkt.number = dpkt_v2.number; dpkt.lat = dpkt_v2.lat; dpkt.lat_mant = dpkt_v2.lat_mant; dpkt.lon = dpkt_v2.lon; dpkt.lon_mant = dpkt_v2.lon_mant; dpkt.alt = dpkt_v2.alt; dpkt.alt_mant = dpkt_v2.alt_mant; dpkt.spd = dpkt_v2.spd; dpkt.spd_mant = dpkt_v2.spd_mant; dpkt.fix = dpkt_v2.fix; dpkt.power = dpkt_v2.power; memcpy(&dpkt.ts, &dpkt_v1.ts, sizeof(time_hdr)); } else { #ifdef HAVE_LIBZ read_ret = gzread(gpsfz, &dpkt, sizeof(dpkt)); #else read_ret = fread(&dpkt, sizeof(dpkt), 1, gpsf); #endif } // We can't trust packets that have no coordinate fix if (dpkt.fix == 0) continue; double lat, lon, alt, spd; // Convert the stored primary+mantissa into a double lat = (double) dpkt.lat + ((double) dpkt.lat_mant / 1000000); lon = (double) dpkt.lon + ((double) dpkt.lon_mant / 1000000); alt = (double) dpkt.alt + ((double) dpkt.alt_mant / 1000000); spd = (double) dpkt.spd + ((double) dpkt.spd_mant / 1000000); if (lat == 0 || lon == 0) continue; // If it's part of a track print it as a track entry if ((dpkt.number == 0xFF && filhdr.version <= 3) || (dpkt.number == HEADER_NUM && filhdr.version > 3)) { fprintf(outf, " \n", gps_track_bssid, (long int) dpkt.ts.tv_sec, (long int) dpkt.ts.tv_usec, lat, lon, alt, spd, dpkt.fix, dpkt.power, dpkt.quality, dpkt.noise); } else { // Otherwise print a normal network fprintf(outf, " \n", Mac2String(net_vec[dpkt.number].header.bssid, ':').c_str(), (long int) dpkt.ts.tv_sec, (long int) dpkt.ts.tv_usec, lat, lon, alt, spd, dpkt.fix, dpkt.power, dpkt.quality, dpkt.noise); } } fprintf(outf, "\n\n"); #ifdef HAVE_LIBZ gzclose(gpsfz); #else fclose(gpsf); #endif fclose(outf); return 1; } int Usage(char *argv) { printf("Usage: %s [OPTION] \n", argv); printf( " -o, --output Output cwgd data to (default stdout)\n" " -n, --netfile Network XML file to reference\n" " -h, --help What do you think you're reading?\n"); exit(1); } char *exec_name; int main(int argc, char *argv[]) { exec_name = argv[0]; static struct option long_options[] = { /* options table */ { "output", required_argument, 0, 'o' }, { "netfile", required_argument, 0, 'n' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int option_index; char *foutname = NULL; char *noutname = NULL; while(1) { int r = getopt_long(argc, argv, "hn:o:", long_options, &option_index); if (r < 0) break; switch(r) { case 'o': foutname = optarg; break; case 'n': noutname = optarg; break; default: Usage(argv[0]); break; } } if (optind == argc) { fprintf(stderr, "FATAL: No gps files given.\n"); exit(1); } if (ProcessGPSFile(argv[optind], foutname, noutname) < 0) { fprintf(stderr, "FATAL: Unrecoverable error processing GPS data file \"%s\".\n", argv[optind]); } exit(0); } kismet-2013-03-R1b/extra/old/cwgd2gpsdrive.sh0000775000175000017500000000060712124602454020470 0ustar dragorndragorn#!/bin/sh # This doesn't work right if test "$1" = ""; then echo "No cwgd files given." exit 1 fi while test "$1" != ""; do if test ! -f $1 -a "$1" != "-"; then echo "Couldn't open $1, skipping." shift continue fi echo "1001.000000 1001.000000 1001 `date`" cat $1 | grep "__TRACK__" | awk -F'\t' '{ printf("%10.6f %10.6f %10.0f %s\n", $3, $4, $5, $11); }' shift done kismet-2013-03-R1b/extra/old/multi-gpsmap.sh0000775000175000017500000000273312124602454020337 0ustar dragorndragorn#!/bin/sh # make a lot of small maps out of a kismet track # this should be the only user-settable parameter scale=1800 awk '/gps-point/ { if ( $3 ~ "source.*" ) { print $6" "$7 } else { print $5" "$6 }}' < $1 | while read line; do eval $line if [[ $lat != 0 ]]; then echo $lat cat > /dev/null break fi done > /tmp/mg$$ latitude=`cat /tmp/mg$$` bc -l << EOF > /tmp/mg$$ scale=3 c(($latitude * 8 * a(1))/360) EOF cos_lat=`cat /tmp/mg$$` rm /tmp/mg$$ awk '/gps-point/ { if ( $3 ~ "source.*" ) { print $6" "$7 } else { print $5" "$6 }}' < $1 | while read line; do eval $line echo $lat $lon done | awk -v cos_lat=$cos_lat -v scale=$scale 'BEGIN {olat=0} { if ( olat == 0 ) { count = 1 trig_dist = scale / 80000000 print "gpsmap -tG -l name,bssid,manuf -c "$1","$2" -s "scale" -o map"count".gif" olat = $1 olon = $2 maxdist = 0 count = count + 1 } else if ( $1 != 0 ) { latdiff = ( $1 - olat ) * cos_lat londiff = $2 - olon dist = latdiff * latdiff + londiff * londiff if ( dist > maxdist ) { maxdist = dist } if ( dist > trig_dist || ( maxdist - dist ) > ( trig_dist / 10) ) { print "gpsmap -tG -l name,bssid,manuf -c "$1","$2" -s "scale" -o map"count".gif" olat = $1 olon = $2 maxdist = 0 count = count + 1 } lastlat = $1 lastlon = $2 } } END { print "gpsmap -tG -l name,bssid,manuf -c "lastlat","lastlon" -s "scale" -o map"count".gif" }' | while read line; do echo $line $1 eval $line $1 done kismet-2013-03-R1b/extra/old/kismetcsv.sql0000664000175000017500000000235712124602454020114 0ustar dragorndragorn# CSV2MySQL support # Updated: Mike Kershaw # Date: 2003/07/24 # Updated: Mike Kerhaw # Date: 2002/07/09 # Author: Reyk Floeter # Date: 2002/03/13 # # create a table to import kismet CSV logs... (MySQL- style) CREATE TABLE kismet ( Network integer, NetType char(15), ESSID varchar(255), BSSID char(17) DEFAULT '00:00:00:00:00:00', Info varchar(255), Channel integer, Cloaked enum("Yes", "No"), WEP enum("Yes", "No"), Decrypted enum("Yes", "No"), Maxrate float, MaxSeenRate float, Beacon integer, LLC integer, Data integer, Crypt integer, Weak integer, Total integer, Carrier varchar(255), Encoding varchar(255), First varchar(255), Last varchar(255), BestQuality integer, BestSignal integer, BestNoise integer, GPSMinLat float, GPSMinLon float, GPSMinAlt float, GPSMinSpd float, GPSMaxLat float, GPSMaxLon float, GPSMaxAlt float, GPSMaxSpd float, GPSBestLat float, GPSBestLon float, GPSBestAlt float, Datasize long integer, IPType varchar(25), IP varchar(15), id int PRIMARY KEY auto_increment ); kismet-2013-03-R1b/extra/kismet-1.0.xsd0000664000175000017500000002740212124602454017113 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet2cwgd.cc0000664000175000017500000002524512124602454017340 0ustar dragorndragorn#include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include #include "getopt.h" #include #include #include #include #include #include #include #include "gpsdump.h" #include "expat.h" string Mac2String(uint8_t *mac, char seperator) { char tempstr[MAC_STR_LEN]; // There must be a better way to do this... if (seperator != '\0') snprintf(tempstr, MAC_STR_LEN, "%02X%c%02X%c%02X%c%02X%c%02X%c%02X", mac[0], seperator, mac[1], seperator, mac[2], seperator, mac[3], seperator, mac[4], seperator, mac[5]); else snprintf(tempstr, MAC_STR_LEN, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); string temp = tempstr; return temp; } int ProcessGPSFile(char *in_fname, char *in_oname) { int file_samples = 0; #ifdef HAVE_LIBZ gzFile gpsfz; #else FILE *gpsf; #endif #ifdef HAVE_LIBZ if ((gpsfz = gzopen(in_fname, "rb")) == NULL) { fprintf(stderr, "FATAL: Could not open data file\n"); return -1; } #else if ((gpsf = fopen(in_fname, "r")) == NULL) { fprintf(stderr, "FATAL: Could not open data file.\n"); return -1; } #endif FILE *outf; if (in_oname == NULL) { outf = stdout; } else { if ((outf = fopen(in_oname, "a")) == NULL) { fprintf(stderr, "FATAL: Could not open output file (%s) for appending\n", in_oname); return -1; } } fprintf(stderr, "NOTICE: Processing gps file '%s'\n", in_fname); vector file_points; #ifdef HAVE_LIBZ file_points = XMLFetchGpsList(gpsfz); #else file_points = XMLFetchGpsList(gpsf); #endif if (file_points.size() == 0) { fprintf(stderr, "WARNING: No sample points found in '%s'.\n", in_fname); } // We handle the points themselves after we handle the network component file_samples = file_points.size(); #ifdef HAVE_LIBZ gzclose(gpsfz); #else fclose(gpsf); #endif // We have all our gps points loaded into the local struct now, so if they had a // network file specified, load the networks from that and mesh it with the network // data we already (may) have from ther files. vector file_networks; int foundnetfile = 0; string comp; if ((comp = XMLFetchGpsNetfile()) != "") { fprintf(stderr, "NOTICE: Reading associated network file, '%s'\n", XMLFetchGpsNetfile().c_str()); #ifdef HAVE_LIBZ if ((gpsfz = gzopen(XMLFetchGpsNetfile().c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open associated network xml file '%s'.\n", XMLFetchGpsNetfile().c_str()); } else { foundnetfile = 1; } // Try our alternate file methods if (foundnetfile == 0) { comp = XMLFetchGpsNetfile(); comp += ".gz"; if ((gpsfz = gzopen(comp.c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open compressed network xml file '%s'\n", comp.c_str()); } else { foundnetfile = 1; } } if (foundnetfile == 0) { string orignetfile = XMLFetchGpsNetfile(); string origxmlfile = in_fname; // Break up the path to the gpsxml file and form a path based on that unsigned int lastslash = 0; for (unsigned int x = origxmlfile.find('/'); x != string::npos; lastslash = x, x = origxmlfile.find('/', lastslash+1)) { // We don't actually need to do anything... } comp = origxmlfile.substr(0, lastslash); lastslash = 0; for (unsigned int x = orignetfile.find('/'); x != string::npos; lastslash = x, x = orignetfile.find('/', lastslash+1)) { // We don't actually need to do anything... } comp += "/" + orignetfile.substr(lastslash, orignetfile.size() - lastslash); if (comp != origxmlfile) { if ((gpsfz = gzopen(comp.c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open network xml file relocated to %s\n", comp.c_str()); } else { foundnetfile = 1; } // And look again for our relocated compressed file. if (foundnetfile == 0) { comp += ".gz"; if ((gpsfz = gzopen(comp.c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open compressed network xml file relocated to %s\n", comp.c_str()); } else { foundnetfile = 1; } } } } #else if ((gpsf = fopen(XMLFetchGpsNetfile().c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open associated network xml file '%s'\n", XMLFetchGpsNetfile().c_str()); } else { foundnetfile = 1; } // Try our alternate file methods if (foundnetfile == 0) { string orignetfile = XMLFetchGpsNetfile(); string origxmlfile = in_fname; // Break up the path to the gpsxml file and form a path based on that unsigned int lastslash = 0; for (unsigned int x = origxmlfile.find('/'); x != string::npos; lastslash = x, x = origxmlfile.find('/', lastslash+1)) { // We don't actually need to do anything... } comp = origxmlfile.substr(0, lastslash); lastslash = 0; for (unsigned int x = orignetfile.find('/'); x != string::npos; lastslash = x, x = orignetfile.find('/', lastslash+1)) { // We don't actually need to do anything... } comp += "/" + orignetfile.substr(lastslash, orignetfile.size() - lastslash - 1); if (comp != origxmlfile) { if ((gpsf = fopen(comp.c_str(), "r")) == NULL) { fprintf(stderr, "WARNING: Could not open network xml file relocated to %s\n", comp.c_str()); } else { foundnetfile = 1; } } } #endif if (foundnetfile) { fprintf(stderr, "NOTICE: Opened associated network xml file '%s'\n", comp.c_str()); fprintf(stderr, "NOTICE: Processing network XML file.\n"); #ifdef HAVE_LIBZ file_networks = XMLFetchNetworkList(gpsfz); #else file_networks = XMLFetchNetworkList(gpsf); #endif if (file_networks.size() == 0) { fprintf(stderr, "WARNING: No network entries found in '%s'.\n", XMLFetchGpsNetfile().c_str()); } #ifdef HAVE_LIBZ gzclose(gpsfz); #else fclose(gpsf); #endif } } time_t now = time(0); fprintf(outf, "# COMMON WIRELESS GPS DATA\n" "# File format 1.0\n" "# Generated by kismet2cwgd on %.24s\n\n" "# BSSID SSID LAT LON ALT SPEED FIX QUALITY POWER NOISE TIME\n\n", ctime(&now)); map bssid_cache; for (unsigned int i = 0; i < file_points.size(); i++) { double lat, lon, alt, spd; int fix; lat = file_points[i]->lat; lon = file_points[i]->lon; alt = file_points[i]->alt; spd = file_points[i]->spd; fix = file_points[i]->fix; now = file_points[i]->tv_sec; if (strncmp(file_points[i]->bssid, gps_track_bssid, MAC_STR_LEN) == 0) { fprintf(outf, "00:00:00:00:00:00\t__TRACK__\t%3.6f\t%3.6f\t%3.6f\t%3.6f\t%d\t%d\t%d\t%d\t%.24s\n", lat, lon, alt, spd, fix, file_points[i]->quality, file_points[i]->signal, file_points[i]->noise, ctime(&now)); } else { char ssid[32] = ""; mac_addr bssid = file_points[i]->bssid; if (bssid_cache.find(bssid) == bssid_cache.end()) { int matched = 0; for (unsigned int f = 0; f < file_networks.size(); f++) { if (bssid == file_networks[f]->bssid) { snprintf(ssid, 32, "%s", file_networks[f]->ssid.c_str()); bssid_cache[bssid] = file_networks[f]; matched = 1; break; } } if (!matched) bssid_cache[bssid] = NULL; } else { if (bssid_cache[bssid] != NULL) snprintf(ssid, 32, "%s", bssid_cache[bssid]->ssid.c_str()); } fprintf(outf, "%s\t%s\t%3.6f\t%3.6f\t%3.6f\t%3.6f\t%d\t%d\t%d\t%d\t%.24s\n", bssid.Mac2String().c_str(), ssid, lat, lon, alt, spd, fix, file_points[i]->quality, file_points[i]->signal, file_points[i]->noise, ctime(&now)); } } fclose(outf); return 1; } int Usage(char *argv) { printf("Usage: %s [OPTION] \n", argv); printf( " -o, --output Output cwgd data to (default stdout)\n" " -h, --help What do you think you're reading?\n"); exit(1); } char *exec_name; int main(int argc, char *argv[]) { exec_name = argv[0]; static struct option long_options[] = { /* options table */ { "output", required_argument, 0, 'o' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int option_index; char *foutname = NULL; while(1) { int r = getopt_long(argc, argv, "ho:", long_options, &option_index); if (r < 0) break; switch(r) { case 'o': foutname = optarg; break; default: Usage(argv[0]); break; } } if (optind == argc) { fprintf(stderr, "FATAL: No gps files given.\n"); exit(1); } for (int x = optind; x < argc; x++) { if (ProcessGPSFile(argv[x], foutname) < 0) { fprintf(stderr, "FATAL: Unrecoverable error processing GPS data file \"%s\".\n", argv[x]); exit(1); } } exit(0); } kismet-2013-03-R1b/extra/kismet-gps-2.9.1.dtd0000664000175000017500000001655512124602454020037 0ustar dragorndragorn kismet-2013-03-R1b/extra/gpsxml-sanitize.cc0000664000175000017500000001021712124602454020244 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include "getopt.h" #include #include #include #include #include #include #include #include #include #include "configfile.h" #include "gpsdump.h" #include "expat.h" #include "manuf.h" #include "gpsmap_samples.h" int verbose = 0; int ProcessGPSFile(char *in_fname) { #ifdef HAVE_LIBZ gzFile gpsfz; #else FILE *gpsf; #endif #ifdef HAVE_LIBZ if ((gpsfz = gzopen(in_fname, "rb")) == NULL) { fprintf(stderr, "FATAL: Could not open data file\n"); return -1; } #else if ((gpsf = fopen(in_fname, "r")) == NULL) { fprintf(stderr, "FATAL: Could not open data file.\n"); return -1; } #endif fprintf(stderr, "\n\nProcessing gps file '%s'\n", in_fname); vector file_points; map file_screen; #ifdef HAVE_LIBZ file_points = XMLFetchGpsList(gpsfz); #else file_points = XMLFetchGpsList(gpsf); #endif if (file_points.size() == 0) { fprintf(stderr, "WARNING: No sample points found in '%s'.\n", in_fname); return 0; } // We handle the points themselves after we handle the network component #ifdef HAVE_LIBZ gzclose(gpsfz); #else fclose(gpsf); #endif time_t xmlct = XMLFetchGpsStart(); fprintf(stderr, "File '%s', version %d, netfile '%s', start time '%.24s'\n", in_fname, (int) XMLFetchGpsVersion(), XMLFetchGpsNetfile().c_str(), ctime(&xmlct)); fprintf(stderr, "Sanitizing %d sample points...\n", file_points.size()); SanitizeSamplePoints(file_points, &file_screen); fprintf(stderr, "Removing %d junk samples...\n", file_screen.size()); printf("\n\n\n"); // Write the start of the run printf("\n\n", GPS_VERSION, ctime(&xmlct)); if (XMLFetchGpsNetfile().length() > 0) { printf(" %s\n\n", XMLFetchGpsNetfile().c_str()); } for (unsigned int x = 0; x < file_points.size(); x++) { if (file_screen.find(file_points[x]->id) != file_screen.end()) continue; printf(" \n", file_points[x]->bssid, file_points[x]->source, (long int) file_points[x]->tv_sec, (long int) file_points[x]->tv_usec, file_points[x]->lat, file_points[x]->lon, file_points[x]->alt, file_points[x]->spd, file_points[x]->heading, file_points[x]->fix, file_points[x]->signal, file_points[x]->noise); } printf("\n"); return 0; } int main(int argc, char *argv[]) { fprintf(stderr, "Kismet GPSXML Sample Sanitizer\n"); fprintf(stderr, "Sanitized XML will be printed to stdout.\n"); if (argc != 2) { fprintf(stderr, "FATAL: Must specifiy only one GPS file.\n"); } ProcessGPSFile(argv[1]); return 0; } kismet-2013-03-R1b/extra/kismet-1.5.dtd0000664000175000017500000002141112124602454017067 0ustar dragorndragorn kismet-2013-03-R1b/extra/kismet-2.9.1.dtd0000664000175000017500000002461112124602454017240 0ustar dragorndragorn kismet-2013-03-R1b/pollable.h0000664000175000017500000000262612124602454015424 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __POLLABLE_H__ #define __POLLABLE_H__ #include "config.h" #include #include #include #include "globalregistry.h" // Basic pollable object that anything that gets fed into the select() // loop in main() should be descended from class Pollable { public: Pollable() { } Pollable(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; } virtual ~Pollable() { } virtual void RegisterGlobals(GlobalRegistry *in_reg) { globalreg = in_reg; } virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) = 0; virtual int Poll(fd_set& in_rset, fd_set& in_wset) = 0; protected: GlobalRegistry *globalreg; }; #endif kismet-2013-03-R1b/Makefile.in0000664000175000017500000003016212124602454015522 0ustar dragorndragorninclude Makefile.inc DEPEND = .depend OBJC_CONTROL_O = darwin_control_wrapper.mo darwin_wificontrol.mo OBJC_LINK = @objc_link@ CAPSOURCES = \ packetsource_pcap.o packetsource_wext.o packetsource_bsdrt.o \ packetsource_drone.o packetsource_ipwlive.o packetsource_airpcap.o \ packetsource_darwin.o packetsource_macusb.o PSO = util.o cygwin_utils.o globalregistry.o ringbuf.o \ messagebus.o configfile.o getopt.o \ filtercore.o ifcontrol.o iwcontrol.o madwifing_control.o nl80211_control.o \ $(OBJC_LINK) \ psutils.o ipc_remote.o soundcontrol.o battery.o kismet_json.o \ netframework.o clinetframework.o tcpserver.o tcpclient.o \ unixdomainserver.o serialclient.o packetsourcetracker.o $(CAPSOURCES) \ kis_netframe.o kis_droneframe.o \ gpswrapper.o gpscore.o gpsdclient.o gpsserial.o gpsfixed.o \ packetchain.o \ plugintracker.o alertracker.o timetracker.o \ packetdissectors.o devicetracker.o netracker.o channeltracker.o \ phy_80211.o \ manuf.o \ dumpfile.o dumpfile_pcap.o dumpfile_gpsxml.o \ dumpfile_tuntap.o dumpfile_netxml.o dumpfile_nettxt.o dumpfile_string.o \ dumpfile_alert.o statealert.o \ kismet_server.o PS = kismet_server DRONEO = util.o cygwin_utils.o globalregistry.o ringbuf.o \ messagebus.o configfile.o getopt.o \ ifcontrol.o iwcontrol.o madwifing_control.o nl80211_control.o $(OBJC_LINK) \ psutils.o ipc_remote.o soundcontrol.o kismet_json.o \ netframework.o clinetframework.o tcpserver.o tcpclient.o serialclient.o \ drone_kisnetframe.o kis_droneframe.o \ gpswrapper.o gpscore.o gpsdclient.o gpsserial.o gpsfixed.o \ packetchain.o \ $(CAPSOURCES) \ plugintracker.o packetsourcetracker.o timetracker.o \ kismet_drone.o CSO = util.o cygwin_utils.o globalregistry.o ringbuf.o \ messagebus.o configfile.o getopt.o \ filtercore.o ifcontrol.o iwcontrol.o madwifing_control.o nl80211_control.o \ $(OBJC_LINK) \ psutils.o ipc_remote.o netframework.o clinetframework.o tcpserver.o tcpclient.o \ timetracker.o drone_kisnetframe.o \ packetsourcetracker.o packetchain.o $(CAPSOURCES) \ dumpfile.o dumpfile_tuntap.o \ kismet_capture.o CS = kismet_capture DRONE = kismet_drone NCO = util.o ringbuf.o globalregistry.o messagebus.o configfile.o getopt.o \ soundcontrol.o timetracker.o ipc_remote.o \ clinetframework.o tcpclient.o popenclient.o kis_clinetframe.o \ text_cliframe.o \ kis_panel_widgets.o kis_panel_network.o \ kis_panel_windows.o kis_panel_details.o \ kis_panel_preferences.o \ kis_panel_frontend.o \ kismet_client.o NC = kismet_client # HOPPERO = util.o configfile.o getopt.o kismet_hopper.o # HOPPER = kismet_hopper BUILDCLIENT=@wantclient@ ALL = Makefile $(DEPEND) $(PS) $(CS) $(DRONE) INSTBINS = $(PS) $(CS) $(DRONE) ifeq ($(BUILDCLIENT), yes) ALL += $(NC) INSTBINS += $(NC) endif all: $(ALL) all-with-plugins: @make plugins-clean @make all @make plugins $(PS): $(PSO) $(CS) $(LD) $(LDFLAGS) -o $(PS) $(PSO) $(LIBS) $(CXXLIBS) $(PCAPLNK) $(KSLIBS) $(CS): $(CSO) $(LD) $(LDFLAGS) -o $(CS) $(CSO) $(LIBS) $(CXXLIBS) $(PCAPLNK) $(CAPLIBS) $(KSLIBS) $(DRONE): $(DRONEO) $(CS) $(LD) $(LDFLAGS) -o $(DRONE) $(DRONEO) $(LIBS) $(CXXLIBS) $(PCAPLNK) $(KSLIBS) $(NC): $(NCO) $(LD) $(LDFLAGS) -o $(NC) $(NCO) $(CXXLIBS) $(CLIENTLIBS) #$(HOPPER): $(HOPPERO) # $(LD) $(LDFLAGS) -o $(HOPPER) $(HOPPERO) Makefile: Makefile.in configure @-echo "'Makefile.in' or 'configure' are more current than this Makefile. You should re-run 'configure'." binsuidinstall: $(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) -m 4550 $(CS) $(BIN)/$(CS); commoninstall: mkdir -p $(ETC) mkdir -p $(BIN) if test -e $(NC); then \ echo "Installing client"; \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 scripts/kismet $(BIN)/kismet; \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(NC) $(BIN)/$(NC); \ fi; $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(PS) $(BIN)/$(PS); $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(DRONE) $(BIN)/$(DRONE); mkdir -p $(MAN)/man1 $(INSTALL) -o $(INSTUSR) -g $(MANGRP) -m 644 man/kismet.1 $(MAN)/man1/kismet.1 $(INSTALL) -o $(INSTUSR) -g $(MANGRP) -m 644 man/kismet_drone.1 $(MAN)/man1/kismet_drone.1 mkdir -p $(MAN)/man5 $(INSTALL) -o $(INSTUSR) -g $(MANGRP) -m 644 man/kismet.conf.5 $(MAN)/man5/kismet.conf.5 $(INSTALL) -o $(INSTUSR) -g $(MANGRP) -m 644 man/kismet_drone.conf.5 $(MAN)/man5/kismet_drone.conf.5 mkdir -p $(WAV) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 wav/new.wav $(WAV)/new.wav $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 wav/packet.wav $(WAV)/packet.wav $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 wav/alert.wav $(WAV)/alert.wav $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 wav/gpslost.wav $(WAV)/gpslost.wav $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 wav/gpslock.wav $(WAV)/gpslock.wav suidinstall: $(CS) -groupadd -f $(SUIDGROUP) $(MAKE) -e commoninstall $(MAKE) -e binsuidinstall @if test -f $(ETC)/kismet.conf; then \ echo "$(ETC)/kismet.conf already installed, not replacing it. HOWEVER"; \ echo "if there have been any changes to the base config you will need"; \ echo "to add them to your config file."; \ else \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet.conf $(ETC)/kismet.conf; \ echo install -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet.conf $(ETC)/kismet.conf; \ echo "Installed config into $(ETC)/kismet.conf."; \ fi @if test -f $(ETC)/kismet_drone.conf; then \ echo "$(ETC)/kismet_drone.conf already installed, not replacing it. HOWEVER"; \ echo "if there have been any changes to the base config you will need"; \ echo "to add them to your config file."; \ else \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet_drone.conf $(ETC)/kismet_drone.conf; \ echo install -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet_drone.conf $(ETC)/kismet_drone.conf; \ echo "Installed drone config into $(ETC)/kismet_drone.conf."; \ fi @echo "Installed kismet into $(BIN)/." @echo "If you have not done so already, read the README file and the FAQ file. Additional" @echo "documentation is in the docs/ directory. You MUST edit $(ETC)/kismet.conf " @echo "and configure Kismet for your system, or it will NOT run properly!" @echo @echo "Kismet has been installed with a SUID ROOT CAPTURE HELPER executeable by " @echo "users in the group '" $(SUIDGROUP) "'. This WILL ALLOW USERS IN THIS GROUP " @echo "TO ALTER YOUR NETWORK INTERACE STATES, but is more secure than running " @echo "all of Kismet as root. ONLY users in this group will be able to " @echo "run Kismet and capture from physical network devices." install: $(INSTBINS) $(MAKE) -e commoninstall @if test -f $(ETC)/kismet.conf; then \ echo "$(ETC)/kismet.conf already installed, not replacing it. HOWEVER"; \ echo "if there have been any changes to the base config you will need"; \ echo "to add them to your config file."; \ else \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet.conf $(ETC)/kismet.conf; \ echo install -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet.conf $(ETC)/kismet.conf; \ echo "Installed config into $(ETC)/kismet.conf."; \ fi @if test -f $(ETC)/kismet_drone.conf; then \ echo "$(ETC)/kismet_drone.conf already installed, not replacing it. HOWEVER"; \ echo "if there have been any changes to the base config you will need"; \ echo "to add them to your config file."; \ else \ $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet_drone.conf $(ETC)/kismet_drone.conf; \ echo install -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/kismet_drone.conf $(ETC)/kismet_drone.conf; \ echo "Installed drone config into $(ETC)/kismet_drone.conf."; \ fi @echo "Installed kismet into $(BIN)/." @echo "If you have not done so already, read the README file and the FAQ file. Additional" @echo "documentation is in the docs/ directory. You MUST edit $(ETC)/kismet.conf " @echo "and configure Kismet for your system, or it will NOT run properly!" @echo @echo "Kismet has NOT been installed suid-root. This means you will need to start " @echo "it as root. If you add your user to the $(SUIDGROUP) group and install " @echo "Kismet with 'make suidinstall', users in that group will be able to " @echo "run Kismet directly." @echo @echo "READ THE KISMET DOCUMENTATION ABOUT THE KISMET SECURITY MODEL TO" @echo "DECIDE IF YOU WANT TO INSTALL IT SUID-ROOT" @echo @echo "It is generally more secure to install Kismet with the suid-root helper " @echo "option." rpm: @echo "Disabling SUID installation (RPM will handle setting the SUID bit.)" @( export SUID="no"; export INSTGRP=`id -g`; export MANGRP=`id -g`; \ export INSTUSR=`id -u`; $(MAKE) -e install ) clean: @-rm -f *.o *.mo @-$(MAKE) all-plugins-clean @-rm -f $(PS) @-rm -f $(CS) @-rm -f $(DRONE) @-rm -f $(NC) distclean: @-$(MAKE) clean @-$(MAKE) all-plugins-clean @-rm -f *~ @-rm -f $(DEPEND) @-rm -f config.status @-rm -f config.h @-rm -f config.log @-rm -rf packaging/ipkg/usr @-rm -rf packaging/pak @-rm -rf *.ipk @-rm -f scripts/kismet @-rm -f Makefile ipkg: $(PS) $(NC) @if test "`whoami`" != "root"; then echo "Warning: You are not root. The ipkg will probably not be what you want."; fi @mkdir -p packaging/ipkg/$(ETC) @mkdir -p packaging/ipkg/$(BIN) @arm-linux-strip $(PS) @arm-linux-strip $(NC) # @arm-linux-strip $(HOPPER) @cp $(PS) packaging/ipkg/$(BIN)/$(PS) @cp $(NC) packaging/ipkg/$(BIN)/$(NC) # @cp $(HOPPER) packaging/ipkg/$(BIN)/$(HOPPER) @cp scripts/kismet packaging/ipkg/$(BIN)/kismet @cp conf/kismet.conf packaging/ipkg/$(ETC)/kismet.conf @chmod a+x packaging/ipkg/$(BIN)/* @chown root.root packaging/ipkg -R @echo "Making ipkg..." @rm -rf packaging/pak @mkdir -p packaging/pak @( cd packaging/ipkg/CONTROL; tar cf ../../pak/control.tar ./control; ) @( cd packaging/ipkg/; tar cf ../pak/data.tar ./usr; ) @( cd packaging/pak; gzip control.tar; gzip data.tar; tar cf ../../kismet_arm.tar ./control.tar.gz ./data.tar.gz; ) @( gzip -c kismet_arm.tar > kismet_$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_TINY)_arm.ipk; rm kismet_arm.tar; ) dep: @$(MAKE) depend depend: Makefile @$(MAKE) $(DEPEND) $(DEPEND): Makefile @-rm -f $(DEPEND) @echo "Generating dependencies... " @echo > $(DEPEND) @$(CXX) $(CFLAGS) -MM \ `echo $(PSO) $(DRONEO) $(NCO) | \ sed -e "s/\.o/\.cc/g" | sed -e "s/\.mo/\.m/g"` >> $(DEPEND) plugins: Makefile @( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do echo "PLUGIN: $$x"; ( cd "$$x"; make; ); done ) restricted-plugins: Makefile @( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do echo "PLUGIN: $$x"; ( cd "$$x"; make; ); done ) plugins-clean: @( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do echo "PLUGIN-CLEAN: $$x"; ( cd "$$x"; make clean; ); done ) restricted-plugins-clean: @( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do echo "PLUGIN-CLEAN: $$x"; ( cd "$$x"; make clean; ); done ) plugins-install: Makefile @( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do echo "PLUGIN-INSTALL: $$x"; ( cd "$$x"; make install; ); done ) restricted-plugins-install: Makefile @( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do echo "PLUGIN-INSTALL: $$x"; ( cd "$$x"; make install; ); done ) plugins-userinstall: Makefile @( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do echo "PLUGIN-USERINSTALL: $$x"; ( cd "$$x"; make userinstall; ); done ) restricted-plugins-userinstall: Makefile @( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do echo "PLUGIN-USERINSTALL: $$x"; ( cd "$$x"; make userinstall; ); done ) all-plugins: Makefile @$(MAKE) plugins @$(MAKE) restricted-plugins all-plugins-install: Makefile @$(MAKE) plugins-install @$(MAKE) restricted-plugins-install all-plugins-userinstall: Makefile @$(MAKE) plugins-userinstall @$(MAKE) restricted-plugins-userinstall all-plugins-clean: Makefile @$(MAKE) plugins-clean @$(MAKE) restricted-plugins-clean include $(DEPEND) .c.o: $(DEPEND) $(CC) $(CFLAGS) -c $*.c -o $@ .cc.o: $(DEPEND) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .m.mo: $(DEPEND) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.m -o $@ check-libpcap-nl: @$(REALLD) -lpcap -o check-libpcap-nl.so 2>/dev/null @ldd check-libpcap-nl.so | grep libnl.so | awk '{ print $$1 }' > $@ @rm check-libpcap-nl.so @test "`cat $@`" = "" || \ (echo "It looks like your libpcap links libnl"; rm $@; exit 1) .SUFFIXES: .c .cc .o .m .mo kismet-2013-03-R1b/netracker.cc0000664000175000017500000027710312124602454015752 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "netracker.h" #include "packet.h" #include "gpsdclient.h" #include "alertracker.h" #include "manuf.h" #include "packetsource.h" // TCP server hooks const char *BSSID_fields_text[] = { "bssid", "type", "llcpackets", "datapackets", "cryptpackets", "manuf", "channel", "firsttime", "lasttime", "atype", "rangeip", "netmaskip", "gatewayip", "gpsfixed", "minlat", "minlon", "minalt", "minspd", "maxlat", "maxlon", "maxalt", "maxspd", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", "bestlat", "bestlon", "bestalt", "agglat", "agglon", "aggalt", "aggpoints", "datasize", "turbocellnid", "turbocellmode", "turbocellsat", "carrierset", "maxseenrate", "encodingset", "decrypted", "dupeivpackets", "bsstimestamp", "cdpdevice", "cdpport", "fragments", "retries", "newpackets", "freqmhz", "datacryptset", NULL }; const char *SSID_fields_text[] = { "mac", "checksum", "type", "ssid", "beaconinfo", "cryptset", "cloaked", "firsttime", "lasttime", "maxrate", "beaconrate", "packets", "beacons", "dot11d", NULL }; const char *BSSIDSRC_fields_text[] = { "bssid", "uuid", "lasttime", "numpackets", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", NULL }; const char *CLISRC_fields_text[] = { "bssid", "mac", "uuid", "lasttime", "numpackets", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", NULL }; const char *NETTAG_fields_text[] = { "bssid", "tag", "value", NULL }; const char *CLITAG_fields_text[] = { "bssid", "mac", "tag", "value", NULL }; const char *REMOVE_fields_text[] = { "bssid", NULL }; const char *CLIENT_fields_text[] = { "bssid", "mac", "type", "firsttime", "lasttime", "manuf", "llcpackets", "datapackets", "cryptpackets", "gpsfixed", "minlat", "minlon", "minalt", "minspd", "maxlat", "maxlon", "maxalt", "maxspd", "agglat", "agglon", "aggalt", "aggpoints", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", "bestlat", "bestlon", "bestalt", "atype", "ip", "gatewayip", "datasize", "maxseenrate", "encodingset", "carrierset", "decrypted", "channel", "fragments", "retries", "newpackets", "freqmhz", "cdpdevice", "cdpport", "dot11d", "dhcphost", "dhcpvendor", "datacryptset", NULL }; mac_addr bcast_mac = mac_addr("FF:FF:FF:FF:FF:FF"); int Protocol_BSSID(PROTO_PARMS) { Netracker::tracked_network *net = (Netracker::tracked_network *) data; ostringstream osstr; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= BSSID_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case BSSID_bssid: scratch = net->bssid.Mac2String(); out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_type: osstr << net->type; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_llcpackets: osstr << net->llc_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_datapackets: osstr << net->data_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_cryptpackets: osstr << net->crypt_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_manuf: out_string += "\001" + net->manuf + "\001"; cache->Cache(fnum, "\001" + net->manuf + "\001"); break; case BSSID_channel: osstr << net->channel; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_freqmhz: /* Annoying packed field */ for (map::const_iterator fmi = net->freq_mhz_map.begin(); fmi != net->freq_mhz_map.end(); ++fmi) { osstr << fmi->first << ":" << fmi->second << "*"; } out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_firsttime: osstr << (int) net->first_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_lasttime: osstr << (int) net->last_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_atype: osstr << (int) net->guess_ipdata.ip_type; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_rangeip: scratch = inet_ntoa(net->guess_ipdata.ip_addr_block); out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_netmaskip: scratch = inet_ntoa(net->guess_ipdata.ip_netmask); out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_gatewayip: scratch = inet_ntoa(net->guess_ipdata.ip_gateway); out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_gpsfixed: osstr << net->gpsdata.gps_valid; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minlat: osstr << net->gpsdata.min_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minlon: osstr << net->gpsdata.min_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minalt: osstr << net->gpsdata.min_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minspd: osstr << net->gpsdata.min_spd; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxlat: osstr << net->gpsdata.max_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxlon: osstr << net->gpsdata.max_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxalt: osstr << net->gpsdata.max_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxspd: osstr << net->gpsdata.max_spd; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_signal_dbm: osstr << net->snrdata.last_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minsignal_dbm: osstr << net->snrdata.min_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxsignal_dbm: osstr << net->snrdata.max_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_noise_dbm: osstr << net->snrdata.last_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minnoise_dbm: osstr << net->snrdata.min_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxnoise_dbm: osstr << net->snrdata.max_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_signal_rssi: osstr << net->snrdata.last_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minsignal_rssi: osstr << net->snrdata.min_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxsignal_rssi: osstr << net->snrdata.max_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_noise_rssi: osstr << net->snrdata.last_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_minnoise_rssi: osstr << net->snrdata.min_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxnoise_rssi: osstr << net->snrdata.max_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_bestlat: osstr << net->snrdata.peak_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_bestlon: osstr << net->snrdata.peak_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_bestalt: osstr << net->snrdata.peak_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_agglat: osstr << net->gpsdata.aggregate_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_agglon: osstr << net->gpsdata.aggregate_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_aggalt: osstr << net->gpsdata.aggregate_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_aggpoints: osstr << net->gpsdata.aggregate_points; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_datasize: osstr << net->datasize; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_tcnid: // FIXME turbocell out_string += "0"; cache->Cache(fnum, "0"); break; case BSSID_tcmode: case BSSID_tsat: // FIXME turbocell out_string += "0"; cache->Cache(fnum, "0"); break; case BSSID_carrierset: osstr << net->snrdata.carrierset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_maxseenrate: osstr << net->snrdata.maxseenrate; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_encodingset: osstr << net->snrdata.encodingset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_decrypted: osstr << net->decrypted; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_dupeiv: osstr << net->dupeiv_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_bsstimestamp: osstr << net->bss_timestamp; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_cdpdevice: if (net->cdp_dev_id.length() == 0) scratch = "\001 \001"; else scratch = "\001" + net->cdp_dev_id + "\001"; out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_cdpport: if (net->cdp_port_id.length() == 0) scratch = "\001 \001"; else scratch = "\001" + net->cdp_port_id + "\001"; out_string += scratch; cache->Cache(fnum, scratch); break; case BSSID_fragments: osstr << net->fragments; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_retries: osstr << net->retries; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_newpackets: osstr << net->new_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case BSSID_datacryptset: osstr << net->data_cryptset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; } // print the newly filled in cache out_string += " "; } return 1; } int Protocol_SSID(PROTO_PARMS) { Netracker::adv_ssid_data *ssid = (Netracker::adv_ssid_data *) data; ostringstream osstr; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= SSID_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case SSID_mac: scratch = ssid->mac.Mac2String(); out_string += scratch; cache->Cache(fnum, scratch); break; case SSID_checksum: osstr << ssid->checksum; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_type: osstr << ssid->type; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_ssid: osstr << "\001" << ssid->ssid << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_beaconinfo: if (ssid->beacon_info.length() == 0) osstr << "\001 \001"; else osstr << "\001" << ssid->beacon_info << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_cryptset: osstr << ssid->cryptset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_cloaked: osstr << ssid->ssid_cloaked; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_firsttime: osstr << ssid->first_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_lasttime: osstr << ssid->last_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_maxrate: osstr << ssid->maxrate; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_beaconrate: osstr << ssid->beaconrate; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_packets: osstr << ssid->packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_beacons: osstr << ssid->beacons; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case SSID_dot11d: // Complex packed field (suck, I know): // \001 COUNTRYCODE:start-num-dbm:start-num-dbm:.. \001 osstr << "\001" + ssid->dot11d_country << ":"; for (unsigned int z = 0; z < ssid->dot11d_vec.size(); z++) { osstr << ssid->dot11d_vec[z].startchan << "-" << ssid->dot11d_vec[z].numchan << "-" << ssid->dot11d_vec[z].txpower << ":"; } osstr << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; } // print the newly filled in cache out_string += " "; } return 1; } // client records. data = CLIENT_data int Protocol_CLIENT(PROTO_PARMS) { Netracker::tracked_client *cli = (Netracker::tracked_client *) data; ostringstream osstr; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= CLIENT_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case CLIENT_bssid: scratch = cli->bssid.Mac2String(); out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_mac: scratch = cli->mac.Mac2String(); out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_type: osstr << (int) cli->type; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_firsttime: osstr << (int) cli->first_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_lasttime: osstr << (int) cli->last_time; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_manuf: out_string += "\001" + cli->manuf + "\001"; cache->Cache(fnum, "\001" + cli->manuf + "\001"); break; case CLIENT_llcpackets: osstr << cli->llc_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_datapackets: osstr << cli->data_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_cryptpackets: osstr << cli->crypt_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_gpsfixed: osstr << cli->gpsdata.gps_valid; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minlat: osstr << cli->gpsdata.min_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minlon: osstr << cli->gpsdata.min_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minalt: osstr << cli->gpsdata.min_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minspd: osstr << cli->gpsdata.min_spd; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxlat: osstr << cli->gpsdata.max_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxlon: osstr << cli->gpsdata.max_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxalt: osstr << cli->gpsdata.max_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxspd: osstr << cli->gpsdata.max_spd; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_signal_dbm: osstr << cli->snrdata.last_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minsignal_dbm: osstr << cli->snrdata.min_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxsignal_dbm: osstr << cli->snrdata.max_signal_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_noise_dbm: osstr << cli->snrdata.last_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minnoise_dbm: osstr << cli->snrdata.min_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxnoise_dbm: osstr << cli->snrdata.max_noise_dbm; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_signal_rssi: osstr << cli->snrdata.last_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minsignal_rssi: osstr << cli->snrdata.min_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxsignal_rssi: osstr << cli->snrdata.max_signal_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_noise_rssi: osstr << cli->snrdata.last_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_minnoise_rssi: osstr << cli->snrdata.min_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxnoise_rssi: osstr << cli->snrdata.max_noise_rssi; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_bestlat: osstr << cli->snrdata.peak_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_bestlon: osstr << cli->snrdata.peak_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_bestalt: osstr << cli->snrdata.peak_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_agglat: osstr << cli->gpsdata.aggregate_lat; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_agglon: osstr << cli->gpsdata.aggregate_lon; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_aggalt: osstr << cli->gpsdata.aggregate_alt; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_aggpoints: osstr << cli->gpsdata.aggregate_points; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_atype: osstr << (int) cli->guess_ipdata.ip_type; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_ip: scratch = inet_ntoa(cli->guess_ipdata.ip_addr_block); out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_gatewayip: scratch = inet_ntoa(cli->guess_ipdata.ip_gateway); out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_datasize: osstr << (int) cli->datasize; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_maxseenrate: osstr << cli->snrdata.maxseenrate; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_encodingset: osstr << cli->snrdata.encodingset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_carrierset: osstr << cli->snrdata.carrierset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_decrypted: osstr << cli->decrypted; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_channel: osstr << cli->channel; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_freqmhz: /* Annoying packed field */ for (map::const_iterator fmi = cli->freq_mhz_map.begin(); fmi != cli->freq_mhz_map.end(); ++fmi) { osstr << fmi->first << ":" << fmi->second << "*"; } out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_fragments: osstr << cli->fragments; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_retries: osstr << cli->retries; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_newpackets: osstr << cli->new_packets; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_cdpdevice: if (cli->cdp_dev_id.length() == 0) scratch = "\001 \001"; else scratch = "\001" + cli->cdp_dev_id + "\001"; out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_cdpport: if (cli->cdp_port_id.length() == 0) scratch = "\001 \001"; else scratch = "\001" + cli->cdp_port_id + "\001"; out_string += scratch; cache->Cache(fnum, scratch); break; case CLIENT_dot11d: osstr << "\001" << cli->dot11d_country << ":"; for (unsigned int z = 0; z < cli->dot11d_vec.size(); z++) { osstr << cli->dot11d_vec[z].startchan << "-" << cli->dot11d_vec[z].numchan << "-" << cli->dot11d_vec[z].txpower << ":"; osstr << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); } break; case CLIENT_dhcphost: osstr << "\001" << cli->dhcp_host << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_dhcpvendor: osstr << "\001" << cli->dhcp_vendor << "\001"; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; case CLIENT_datacryptset: osstr << cli->data_cryptset; out_string += osstr.str(); cache->Cache(fnum, osstr.str()); break; } // print the newly filled in cache out_string += " "; } return 1; } int Protocol_BSSIDSRC(PROTO_PARMS) { Netracker::source_data *sd = (Netracker::source_data *) data; ostringstream osstr; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= BSSIDSRC_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case BSSIDSRC_bssid: scratch = sd->bssid.Mac2String().c_str(); break; case BSSIDSRC_uuid: scratch = sd->source_uuid.UUID2String().c_str(); break; case BSSIDSRC_lasttime: scratch = IntToString(sd->last_seen); break; case BSSIDSRC_numpackets: scratch = IntToString(sd->num_packets); break; case BSSIDSRC_signal_dbm: scratch = IntToString(sd->snrdata.last_signal_dbm); break; case BSSIDSRC_minsignal_dbm: scratch = IntToString(sd->snrdata.min_signal_dbm); break; case BSSIDSRC_maxsignal_dbm: scratch = IntToString(sd->snrdata.max_signal_dbm); break; case BSSIDSRC_noise_dbm: scratch = IntToString(sd->snrdata.last_noise_dbm); break; case BSSIDSRC_minnoise_dbm: scratch = IntToString(sd->snrdata.min_noise_dbm); break; case BSSIDSRC_maxnoise_dbm: scratch = IntToString(sd->snrdata.max_noise_dbm); break; case BSSIDSRC_signal_rssi: scratch = IntToString(sd->snrdata.last_signal_rssi); break; case BSSIDSRC_minsignal_rssi: scratch = IntToString(sd->snrdata.min_signal_rssi); break; case BSSIDSRC_maxsignal_rssi: scratch = IntToString(sd->snrdata.max_signal_rssi); break; case BSSIDSRC_noise_rssi: scratch = IntToString(sd->snrdata.last_noise_rssi); break; case BSSIDSRC_minnoise_rssi: scratch = IntToString(sd->snrdata.min_noise_rssi); break; case BSSIDSRC_maxnoise_rssi: scratch = IntToString(sd->snrdata.max_noise_rssi); break; } out_string += scratch; cache->Cache(fnum, scratch); // print the newly filled in cache out_string += " "; } return 1; } // Reuse the same struct for net and client tags struct nettag_struct { mac_addr bssid; mac_addr mac; map::const_iterator mi; }; int Protocol_NETTAG(PROTO_PARMS) { nettag_struct *s = (nettag_struct *) data; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= NETTAG_maxfield) { out_string = "Unknown field requested."; return -1; } // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch (fnum) { case NETTAG_bssid: scratch = s->bssid.Mac2String().c_str(); break; case NETTAG_tag: scratch = "\001" + s->mi->first + "\001"; break; case NETTAG_value: scratch = "\001" + s->mi->second + "\001"; break; } out_string += scratch; cache->Cache(fnum, scratch); out_string += " "; } return 1; } void Protocol_NETTAG_enable(PROTO_ENABLE_PARMS) { // Push new networks and reset their rate counters for (Netracker::track_iter x = globalreg->netracker->tracked_map.begin(); x != globalreg->netracker->tracked_map.end(); ++x) { Netracker::tracked_network *net = x->second; if (net->type == network_remove) continue; for (map::const_iterator ai = net->arb_tag_map.begin(); ai != net->arb_tag_map.end(); ++ai) { nettag_struct s; s.bssid = net->bssid; s.mi = ai; kis_protocol_cache cache; if (globalreg->kisnetserver->SendToClient(in_fd, globalreg->netracker->proto_ref_nettag, (void *) &s, &cache) < 0) break; } } } int Protocol_CLITAG(PROTO_PARMS) { nettag_struct *s = (nettag_struct *) data; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= CLITAG_maxfield) { out_string = "Unknown field requested."; return -1; } // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case CLITAG_bssid: scratch = s->bssid.Mac2String().c_str(); break; case CLITAG_mac: scratch = s->mac.Mac2String().c_str(); break; case CLITAG_tag: scratch = "\001" + s->mi->first + "\001"; break; case CLITAG_value: scratch = "\001" + s->mi->second + "\001"; break; } out_string += scratch; cache->Cache(fnum, scratch); out_string += " "; } return 1; } void Protocol_CLITAG_enable(PROTO_ENABLE_PARMS) { // Push new networks and reset their rate counters for (Netracker::track_iter x = globalreg->netracker->tracked_map.begin(); x != globalreg->netracker->tracked_map.end(); ++x) { if (x->second->type == network_remove) continue; for (Netracker::client_iter c = x->second->client_map.begin(); c != x->second->client_map.end(); ++c) { for (map::const_iterator ai = c->second->arb_tag_map.begin(); ai != c->second->arb_tag_map.end(); ++ai) { nettag_struct s; s.bssid = x->second->bssid; s.mac = c->second->mac; s.mi = ai; kis_protocol_cache cache; if (globalreg->kisnetserver->SendToClient(in_fd, globalreg->netracker->proto_ref_clitag, (void *) &s, &cache) < 0) break; } } } } int Protocol_CLISRC(PROTO_PARMS) { Netracker::source_data *sd = (Netracker::source_data *) data; ostringstream osstr; string scratch; // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= CLISRC_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case CLISRC_bssid: scratch = sd->bssid.Mac2String().c_str(); break; case CLISRC_mac: scratch = sd->mac.Mac2String().c_str(); break; case CLISRC_uuid: scratch = sd->source_uuid.UUID2String().c_str(); break; case CLISRC_lasttime: scratch = IntToString(sd->last_seen); break; case CLISRC_numpackets: scratch = IntToString(sd->num_packets); break; case CLISRC_signal_dbm: scratch = IntToString(sd->snrdata.last_signal_dbm); break; case CLISRC_minsignal_dbm: scratch = IntToString(sd->snrdata.min_signal_dbm); break; case CLISRC_maxsignal_dbm: scratch = IntToString(sd->snrdata.max_signal_dbm); break; case CLISRC_noise_dbm: scratch = IntToString(sd->snrdata.last_noise_dbm); break; case CLISRC_minnoise_dbm: scratch = IntToString(sd->snrdata.min_noise_dbm); break; case CLISRC_maxnoise_dbm: scratch = IntToString(sd->snrdata.max_noise_dbm); break; case CLISRC_signal_rssi: scratch = IntToString(sd->snrdata.last_signal_rssi); break; case CLISRC_minsignal_rssi: scratch = IntToString(sd->snrdata.min_signal_rssi); break; case CLISRC_maxsignal_rssi: scratch = IntToString(sd->snrdata.max_signal_rssi); break; case CLISRC_noise_rssi: scratch = IntToString(sd->snrdata.last_noise_rssi); break; case CLISRC_minnoise_rssi: scratch = IntToString(sd->snrdata.min_noise_rssi); break; case CLISRC_maxnoise_rssi: scratch = IntToString(sd->snrdata.max_noise_rssi); break; } out_string += scratch; cache->Cache(fnum, scratch); // print the newly filled in cache out_string += " "; } return 1; } int Protocol_REMOVE(PROTO_PARMS) { string *str = (string *) data; out_string += *str; return 1; } void Protocol_BSSID_enable(PROTO_ENABLE_PARMS) { // Push new networks and reset their rate counters for (Netracker::track_iter x = globalreg->netracker->tracked_map.begin(); x != globalreg->netracker->tracked_map.end(); ++x) { Netracker::tracked_network *net = x->second; int filtered = 0; if (net->type == network_remove) continue; // Filter on bssid if (globalreg->netracker->netcli_filter->RunFilter(net->bssid, mac_addr(0), mac_addr(0))) continue; // Do the ADVSSID push inside the BSSID timer kick, because we want // to still allow filtering on the SSID... // TODO: Add filter state caching map::iterator asi; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (globalreg->netracker->netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } if (filtered) continue; kis_protocol_cache cache; if (globalreg->kisnetserver->SendToClient(in_fd, _NPM(PROTO_REF_BSSID), (void *) net, &cache) < 0) break; } } void Protocol_SSID_enable(PROTO_ENABLE_PARMS) { // Push new networks and reset their rate counters for (Netracker::track_iter x = globalreg->netracker->tracked_map.begin(); x != globalreg->netracker->tracked_map.end(); ++x) { Netracker::tracked_network *net = x->second; int filtered = 0; if (net->type == network_remove) continue; // Filter on bssid if (globalreg->netracker->netcli_filter->RunFilter(net->bssid, mac_addr(0), mac_addr(0))) continue; // Do the ADVSSID push inside the BSSID timer kick, because we want // to still allow filtering on the SSID... // TODO: Add filter state caching map::iterator asi; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (globalreg->netracker->netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } if (filtered) continue; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { kis_protocol_cache cache; if (globalreg->kisnetserver->SendToClient(in_fd, _NPM(PROTO_REF_SSID), (void *) asi->second, &cache) < 0) break; } } } void Protocol_CLIENT_enable(PROTO_ENABLE_PARMS) { // Push new networks and reset their rate counters for (Netracker::track_iter x = globalreg->netracker->tracked_map.begin(); x != globalreg->netracker->tracked_map.end(); ++x) { Netracker::tracked_network *net = x->second; int filtered = 0; if (net->type == network_remove) continue; // Filter on bssid if (globalreg->netracker->netcli_filter->RunFilter(net->bssid, mac_addr(0), mac_addr(0))) continue; // Do the ADVSSID push inside the BSSID timer kick, because we want // to still allow filtering on the SSID... // TODO: Add filter state caching map::iterator asi; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (globalreg->netracker->netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } if (filtered) continue; for (Netracker::client_iter c = net->client_map.begin(); c != net->client_map.end(); ++c) { if (c->second->type == client_remove) continue; kis_protocol_cache cache; if (globalreg->kisnetserver->SendToClient(in_fd, _NPM(PROTO_REF_CLIENT), (void *) c->second, &cache) < 0) break; } } } int Netracker_Clicmd_ADDFILTER(CLIENT_PARMS) { if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal addfilter request"); return -1; } Netracker *netr = (Netracker *) auxptr; if (netr->AddFilter((*parsedcmdline)[0].word) < 0) { snprintf(errstr, 1024, "Failed to insert filter string"); return -1; } _MSG("Added network filter '" + (*parsedcmdline)[0].word + "'", MSGFLAG_INFO); return 1; } int Netracker_Clicmd_ADDNETCLIFILTER(CLIENT_PARMS) { if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal addnetclifilter request"); return -1; } Netracker *netr = (Netracker *) auxptr; if (netr->AddNetcliFilter((*parsedcmdline)[0].word) < 0) { snprintf(errstr, 1024, "Failed to insert filter string"); return -1; } _MSG("Added network client filter '" + (*parsedcmdline)[0].word + "'", MSGFLAG_INFO); return 1; } int Netracker_Clicmd_ADDNETTAG(CLIENT_PARMS) { int persist = 0; if (parsedcmdline->size() < 4) { snprintf(errstr, 1024, "Illegal ADDNETTAG request, expected BSSID " "PERSIST TAG VALUES"); return -1; } mac_addr net = mac_addr((*parsedcmdline)[0].word.c_str()); if (net.error) { snprintf(errstr, 1024, "Illegal ADDNETTAG request, expected BSSID " "PERSIST TAG VALUES"); return -1; } if ((*parsedcmdline)[1].word != "0") persist = 1; string content; for (unsigned int x = 3; x < parsedcmdline->size(); x++) { content += (*parsedcmdline)[x].word; if (x < parsedcmdline->size() - 1) content += " "; } ((Netracker *) auxptr)->SetNetworkTag(net, (*parsedcmdline)[2].word, content, persist); return 1; } int Netracker_Clicmd_DELNETTAG(CLIENT_PARMS) { if (parsedcmdline->size() < 2) { snprintf(errstr, 1024, "Illegal DELNETTAG request, expected BSSID TAG"); return -1; } mac_addr net = mac_addr((*parsedcmdline)[0].word.c_str()); if (net.error) { snprintf(errstr, 1024, "Illegal DELNETTAG request, expected BSSID TAG"); return -1; } ((Netracker *) auxptr)->ClearNetworkTag(net, (*parsedcmdline)[1].word); return 1; } int Netracker_Clicmd_ADDCLITAG(CLIENT_PARMS) { int persist = 0; if (parsedcmdline->size() < 5) { snprintf(errstr, 1024, "Illegal ADDCLITAG request, expected BSSID MAC PERSIST " "TAG VALUES"); return -1; } mac_addr net = mac_addr((*parsedcmdline)[0].word.c_str()); if (net.error) { snprintf(errstr, 1024, "Illegal ADDCLITAG request, expected BSSID MAC PERSIST " "TAG VALUES"); return -1; } mac_addr cli = mac_addr((*parsedcmdline)[1].word.c_str()); if (cli.error) { snprintf(errstr, 1024, "Illegal ADDCLITAG request, expected BSSID MAC PERSIST " "TAG VALUES"); return -1; } if ((*parsedcmdline)[2].word != "0") persist = 1; string content; for (unsigned int x = 4; x < parsedcmdline->size(); x++) { content += (*parsedcmdline)[x].word; if (x < parsedcmdline->size() - 1) content += " "; } ((Netracker *) auxptr)->SetClientTag(net, cli, (*parsedcmdline)[3].word, content, persist); return 1; } int Netracker_Clicmd_DELCLITAG(CLIENT_PARMS) { if (parsedcmdline->size() < 3) { snprintf(errstr, 1024, "Illegal DELCLITAG request, expected BSSID MAC TAG"); return -1; } mac_addr net = mac_addr((*parsedcmdline)[0].word.c_str()); if (net.error) { snprintf(errstr, 1024, "Illegal DELCLITAG request, expected BSSID MAC TAG"); return -1; } mac_addr cli = mac_addr((*parsedcmdline)[1].word.c_str()); if (cli.error) { snprintf(errstr, 1024, "Illegal DELCLITAG request, expected BSSID MAC TAG"); return -1; } ((Netracker *) auxptr)->ClearClientTag(net, cli, (*parsedcmdline)[2].word); return 1; } // These are both just dropthroughs into the class itself int kis_80211_netracker_hook(CHAINCALL_PARMS) { Netracker *auxptr = (Netracker *) auxdata; return auxptr->netracker_chain_handler(in_pack); } int kis_80211_datatracker_hook(CHAINCALL_PARMS) { Netracker *auxptr = (Netracker *) auxdata; return auxptr->datatracker_chain_handler(in_pack); } int NetrackerUpdateTimer(TIMEEVENT_PARMS) { Netracker *ntr = (Netracker *) parm; return ntr->TimerKick(); } Netracker::Netracker() { fprintf(stderr, "FATAL OOPS: Netracker() called with no global registry\n"); } void Netracker::Usage(char *name) { printf(" *** Kismet Net Tracking Options ***\n"); printf(" --filter-tracker Tracker filtering\n"); } Netracker::Netracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; track_filter = NULL; netcli_filter = NULL; vector filterlines; int ftc = globalreg->getopt_long_num++; static struct option netracker_long_options[] = { { "filter-tracker", required_argument, 0, ftc }, { 0, 0, 0, 0 } }; int option_idx = 0; optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-", netracker_long_options, &option_idx); if (r < 0) break; if (r == ftc) filterlines.push_back(string(optarg)); } // Sanity if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Netracker called while packetchain is NULL\n"); exit(1); } if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: Netracker called while netserver is NULL\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Netracker called while kist_config is NULL\n"); exit(1); } if (globalreg->alertracker == NULL) { fprintf(stderr, "FATAL OOPS: Netracker called while alertracker is NULL\n"); exit(1); } if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: Netracker called while timetracker is NULL\n"); exit(1); } // Register packet components to tie into our tracker _PCM(PACK_COMP_TRACKERNET) = globalreg->packetchain->RegisterPacketComponent("netracker_network"); _PCM(PACK_COMP_TRACKERCLIENT) = globalreg->packetchain->RegisterPacketComponent("netracker_client"); // Register the packet hooks with the chain globalreg->packetchain->RegisterHandler(&kis_80211_netracker_hook, this, CHAINPOS_CLASSIFIER, -100); globalreg->packetchain->RegisterHandler(&kis_80211_datatracker_hook, this, CHAINPOS_CLASSIFIER, -99); track_probenets = 1; // Parse the filtering for the tracker track_filter = new FilterCore(globalreg); if (filterlines.size() != 0) { _MSG("Net tracker filters specified on command line, not loading filters " "from the Kismet config file", MSGFLAG_INFO); } else { filterlines = globalreg->kismet_config->FetchOptVec("filter_tracker"); } for (unsigned int fl = 0; fl < filterlines.size(); fl++) { if (track_filter->AddFilterLine(filterlines[fl]) < 0) { _MSG("Failed to add filter_tracker config line from the Kismet config " "file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } } // Parse the filter for the network client netcli_filter = new FilterCore(globalreg); vector netclifilterlines = globalreg->kismet_config->FetchOptVec("filter_netclient"); for (unsigned int fl = 0; fl < netclifilterlines.size(); fl++) { if (netcli_filter->AddFilterLine(netclifilterlines[fl]) < 0) { _MSG("Failed to add filter_tracker config line from the Kismet config " "file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } } // Parse the SSID alert data vector spoof_vec = globalreg->kismet_config->FetchOptVec("apspoof"); for (unsigned int x = 0; x < spoof_vec.size(); x++) { string name; size_t pos = spoof_vec[x].find(":"); vector opts; ssid_alert_data *ssid_alert = NULL; #ifdef HAVE_LIBPCRE const char *error = NULL, *study_err = NULL; int err_offt; pcre *re = NULL; pcre_extra *study = NULL; #endif if (pos == string::npos || pos >= spoof_vec[x].length() - 1) { _MSG("Malformed apspoof= config line in Kismet config file, expected " "apspoof=name:options, got '" + spoof_vec[x] + "'", MSGFLAG_ERROR); continue; } name = spoof_vec[x].substr(0, pos); if (StringToOpts(spoof_vec[x].substr(pos + 1, spoof_vec[x].length()), ",", &opts) < 0 || opts.size() == 0) { _MSG("Malformed apspoof= alert config line in Kismet config file, expected " "apspoof=name:options, got '" + spoof_vec[x] + "'", MSGFLAG_ERROR); continue; } if (FetchOpt("validmacs", &opts) == "" || (FetchOpt("ssidregex", &opts) == "" && FetchOpt("ssid", &opts) == "")) { _MSG("Malformed apspoof= alert config line expects 'validmacs' option " "and 'ssid' or 'ssidregex' options", MSGFLAG_ERROR); continue; } if (FetchOpt("ssidregex", &opts) != "") { #ifndef HAVE_LIBPCRE _MSG("Kismet was not compiled with PCRE, cannot use 'ssidregex' option " "in an apspoof filter", MSGFLAG_ERROR); continue; #else if ((re = pcre_compile(FetchOpt("ssidregex", &opts).c_str(), 0, &error, &err_offt, NULL)) == NULL) { _MSG("Couldn't parse APSPOOF filter line, invalid PCRE regex " "'" + FetchOpt("ssidregex", &opts) + "', regex failure: " + string(error) + " at " + IntToString(err_offt), MSGFLAG_ERROR); continue; } if ((study = pcre_study(re, 0, &study_err)) == NULL && study_err != NULL) { _MSG("Couldn't parse APSPOOF filter line '" + FetchOpt("ssidregex", &opts) + "', optimization failure: " + string(study_err), MSGFLAG_ERROR); free(re); continue; } #endif } ssid_alert = new ssid_alert_data; ssid_alert->name = name; if (FetchOpt("ssid", &opts) != "") { #ifdef HAVE_LIBPCRE if (re != NULL) { _MSG("Duplicate 'ssid' and 'ssidregex' options in APSPOOF " "filter line, the 'ssidregex' filter will be used.", MSGFLAG_ERROR); } #endif } #ifdef HAVE_LIBPCRE if (re != NULL) { ssid_alert->ssid_re = re; ssid_alert->ssid_study = study; ssid_alert->filter = FetchOpt("ssidregex", &opts); } #endif ssid_alert->ssid = FetchOpt("ssid", &opts); vector macvec = StrTokenize(FetchOpt("validmacs", &opts), ","); int mac_error = 0; for (unsigned int m = 0; m < macvec.size(); m++) { mac_addr ma = mac_addr(macvec[m].c_str()); if (ma.error) { _MSG("Invalid MAC address '" + macvec[m] + "' in 'validmacs' option " "in APSPOOF filter line, ignoring line", MSGFLAG_ERROR); mac_error = 1; break; } ssid_alert->allow_mac_map.insert(ma, 1); } if (mac_error) { #ifdef HAVE_LIBPCRE if (re) pcre_free(re); if (study) pcre_free(study); #endif free(ssid_alert); continue; } apspoof_vec.push_back(ssid_alert); } // Register network protocols with the tcp server _NPM(PROTO_REF_BSSID) = globalreg->kisnetserver->RegisterProtocol("BSSID", 0, 1, BSSID_fields_text, &Protocol_BSSID, &Protocol_BSSID_enable, this); _NPM(PROTO_REF_SSID) = globalreg->kisnetserver->RegisterProtocol("SSID", 0, 1, SSID_fields_text, &Protocol_SSID, &Protocol_SSID_enable, this); _NPM(PROTO_REF_CLIENT) = globalreg->kisnetserver->RegisterProtocol("CLIENT", 0, 1, CLIENT_fields_text, &Protocol_CLIENT, &Protocol_CLIENT_enable, this); proto_ref_bssidsrc = globalreg->kisnetserver->RegisterProtocol("BSSIDSRC", 0, 1, BSSIDSRC_fields_text, &Protocol_BSSIDSRC, NULL, this); proto_ref_clisrc = globalreg->kisnetserver->RegisterProtocol("CLISRC", 0, 1, CLISRC_fields_text, &Protocol_CLISRC, NULL, this); proto_ref_nettag = globalreg->kisnetserver->RegisterProtocol("NETTAG", 0, 1, NETTAG_fields_text, &Protocol_NETTAG, &Protocol_NETTAG_enable, this); proto_ref_clitag = globalreg->kisnetserver->RegisterProtocol("CLITAG", 0, 1, CLITAG_fields_text, &Protocol_CLITAG, &Protocol_CLITAG_enable, this); _NPM(PROTO_REF_REMOVE) = globalreg->kisnetserver->RegisterProtocol("REMOVE", 0, 1, REMOVE_fields_text, &Protocol_REMOVE, NULL, this); // Add the client command addfiltercmd_ref = globalreg->kisnetserver->RegisterClientCommand("ADDTRACKERFILTER", &Netracker_Clicmd_ADDFILTER, this); addnetclifiltercmd_ref = globalreg->kisnetserver->RegisterClientCommand("ADDNETCLIFILTER", &Netracker_Clicmd_ADDNETCLIFILTER, this); addnettagcmd_ref = globalreg->kisnetserver->RegisterClientCommand("ADDNETTAG", &Netracker_Clicmd_ADDNETTAG, this); delnettagcmd_ref = globalreg->kisnetserver->RegisterClientCommand("DELNETTAG", &Netracker_Clicmd_DELNETTAG, this); addclitagcmd_ref = globalreg->kisnetserver->RegisterClientCommand("ADDCLITAG", &Netracker_Clicmd_ADDCLITAG, this); delclitagcmd_ref = globalreg->kisnetserver->RegisterClientCommand("DELCLITAG", &Netracker_Clicmd_DELCLITAG, this); // See if we have some alerts to raise alert_chan_ref = globalreg->alertracker->ActivateConfiguredAlert("CHANCHANGE"); alert_dhcpcon_ref = globalreg->alertracker->ActivateConfiguredAlert("DHCPCONFLICT"); alert_bcastdcon_ref = globalreg->alertracker->ActivateConfiguredAlert("BCASTDISCON"); alert_airjackssid_ref = globalreg->alertracker->ActivateConfiguredAlert("AIRJACKSSID"); alert_wepflap_ref = globalreg->alertracker->ActivateConfiguredAlert("CRYPTODROP"); alert_dhcpname_ref = globalreg->alertracker->ActivateConfiguredAlert("DHCPNAMECHANGE"); alert_dhcpos_ref = globalreg->alertracker->ActivateConfiguredAlert("DHCPOSCHANGE"); alert_adhoc_ref = globalreg->alertracker->ActivateConfiguredAlert("ADHOCCONFLICT"); alert_ssidmatch_ref = globalreg->alertracker->ActivateConfiguredAlert("APSPOOF"); // Register timer kick netrackereventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &NetrackerUpdateTimer, (void *) this); num_packets = num_datapackets = num_cryptpackets = num_errorpackets = num_filterpackets = num_packetdelta = num_llcpackets = 0; // Build the config file conf_save = globalreg->timestamp.tv_sec; ssid_conf = new ConfigFile(globalreg); ssid_conf->ParseConfig(ssid_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir") + "/" + "ssid_map.conf", "", "", 0, 1).c_str()); tag_conf = new ConfigFile(globalreg); tag_conf->ParseConfig(tag_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir") + "/" + "tag.conf", "", "", 0, 1).c_str()); } Netracker::~Netracker() { SaveSSID(); SaveTags(); // FIXME: More cleanup here if (netrackereventid >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(netrackereventid); if (track_filter != NULL) delete track_filter; if (netcli_filter != NULL) delete netcli_filter; } void Netracker::SaveSSID() { int ret; string dir = ssid_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir"), "", "", 0, 1); ret = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); if (ret < 0 && errno != EEXIST) { string err = string(strerror(errno)); _MSG("Failed to create Kismet settings directory " + dir + ": " + err, MSGFLAG_ERROR); } ret = ssid_conf->SaveConfig(ssid_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir") + "/" + "ssid_map.conf", "", "", 0, 1).c_str()); if (ret < 0) _MSG("Could not save SSID map cache, check previous error messages (probably " "no permission to write to the Kismet config directory: " + dir, MSGFLAG_ERROR); } void Netracker::SaveTags() { int ret; string dir = tag_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir"), "", "", 0, 1); ret = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); if (ret < 0 && errno != EEXIST) { string err = string(strerror(errno)); _MSG("Failed to create Kismet settings directory " + dir + ": " + err, MSGFLAG_ERROR); } ret = tag_conf->SaveConfig(tag_conf->ExpandLogPath(globalreg->kismet_config->FetchOpt("configdir") + "/" + "tag.conf", "", "", 0, 1).c_str()); if (ret < 0) _MSG("Could not save tags, check previous error messages (probably " "no permission to write to the Kismet config directory: " + dir, MSGFLAG_ERROR); } int Netracker::AddFilter(string in_filter) { return track_filter->AddFilterLine(in_filter); } int Netracker::AddNetcliFilter(string in_filter) { return netcli_filter->AddFilterLine(in_filter); } void Netracker::SetNetworkTag(mac_addr in_net, string in_tag, string in_data, int in_persistent) { tracked_network *net; track_iter ti; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return; net = ti->second; net->arb_tag_map[in_tag] = in_data; if (in_persistent) { vector tfl = tag_conf->FetchOptVec(in_net.Mac2String()); vector tflp; int repl = 0; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; if (tflp[0].word == in_tag) { repl = 1; tfl[x] = "\001" + in_tag + "\001,\001" + in_data + "\001"; break; } } if (repl == 0) tfl.push_back("\001" + in_tag + "\001,\001" + in_data + "\001"); tag_conf->SetOptVec(in_net.Mac2String(), tfl, globalreg->timestamp.tv_sec); } if (net->dirty == 0) { dirty_net_vec.push_back(net); net->dirty = 1; } } void Netracker::ClearNetworkTag(mac_addr in_net, string in_tag) { track_iter ti; map::iterator si; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return; if ((si = ti->second->arb_tag_map.find(in_tag)) != ti->second->arb_tag_map.end()) { // Set the content to "" so the client gets an update // ti->second->arb_tag_map.erase(si); si->second = ""; if (ti->second->dirty == 0) { dirty_net_vec.push_back(ti->second); ti->second->dirty = 1; } vector tfl = tag_conf->FetchOptVec(in_net.Mac2String()); vector tflp; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; if (tflp[0].word == in_tag) { tfl.erase(tfl.begin() + x); tag_conf->SetOptVec(in_net.Mac2String(), tfl, globalreg->timestamp.tv_sec); break; } } } } string Netracker::GetNetworkTag(mac_addr in_net, string in_tag) { track_iter ti; map::iterator si; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return ""; if ((si = ti->second->arb_tag_map.find(in_tag)) != ti->second->arb_tag_map.end()) { return si->second; } return ""; } void Netracker::SetClientTag(mac_addr in_net, mac_addr in_cli, string in_tag, string in_data, int in_persistent) { tracked_network *net; tracked_client *cli; track_iter ti; client_iter ci; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return; net = ti->second; if ((ci = net->client_map.find(in_cli)) == net->client_map.end()) return; cli = ci->second; cli->arb_tag_map[in_tag] = in_data; if (in_persistent) { vector tfl = tag_conf->FetchOptVec(in_net.Mac2String() + ":" + in_cli.Mac2String()); vector tflp; int repl = 0; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; if (tflp[0].word == in_tag) { repl = 1; tfl[x] = "\001" + in_tag + "\001,\001" + in_data + "\001"; break; } } if (repl == 0) tfl.push_back("\001" + in_tag + "\001,\001" + in_data + "\001"); tag_conf->SetOptVec(in_net.Mac2String() + ":" + in_cli.Mac2String(), tfl, globalreg->timestamp.tv_sec); } if (cli->dirty == 0) { dirty_cli_vec.push_back(cli); cli->dirty = 1; } } void Netracker::ClearClientTag(mac_addr in_net, mac_addr in_cli, string in_tag) { track_iter ti; client_iter ci; map::iterator si; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return; if ((ci = ti->second->client_map.find(in_cli)) == ti->second->client_map.end()) return; if ((si = ci->second->arb_tag_map.find(in_tag)) != ci->second->arb_tag_map.end()) { // Set the content to "" so the client gets an update // ti->second->arb_tag_map.erase(si); si->second = ""; if (ci->second->dirty == 0) { dirty_cli_vec.push_back(ci->second); ci->second->dirty = 1; vector tfl = tag_conf->FetchOptVec(in_net.Mac2String() + ":" + in_cli.Mac2String()); vector tflp; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; if (tflp[0].word == in_tag) { tfl.erase(tfl.begin() + x); tag_conf->SetOptVec(in_net.Mac2String() + ":" + in_cli.Mac2String(), tfl, globalreg->timestamp.tv_sec); } } } } } string Netracker::GetClientTag(mac_addr in_net, mac_addr in_cli, string in_tag) { track_iter ti; client_iter ci; map::iterator si; if ((ti = tracked_map.find(in_net)) == tracked_map.end()) return ""; if ((ci = ti->second->client_map.find(in_cli)) == ti->second->client_map.end()) return ""; if ((si = ci->second->arb_tag_map.find(in_tag)) != ci->second->arb_tag_map.end()) { return si->second; } return ""; } int Netracker::TimerKick() { // Save SSID config file regularly if (globalreg->timestamp.tv_sec - conf_save > 120) { conf_save = globalreg->timestamp.tv_sec; SaveSSID(); SaveTags(); } // Push new networks and reset their rate counters for (unsigned int x = 0; x < dirty_net_vec.size(); x++) { tracked_network *net = dirty_net_vec[x]; int filtered = 0; if (net->type == network_remove) continue; // Filter on bssid if (netcli_filter->RunFilter(net->bssid, mac_addr(0), mac_addr(0))) continue; // Do the ADVSSID push inside the BSSID timer kick, because we want // to still allow filtering on the SSID... // TODO: Add filter state caching map::iterator asi; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } if (filtered) continue; /* if (netcli_filter->RunFilter(net->bssid, mac_addr(0), mac_addr(0)) || netcli_filter->RunPcreFilter(net->ssid)) continue; */ globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_BSSID), (void *) net); for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (asi->second->dirty == 0) continue; globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_SSID), (void *) asi->second); /* Reset dirty and beacon counters */ asi->second->dirty = 0; asi->second->beacons = 0; } for (map::iterator sdi = net->source_map.begin(); sdi != net->source_map.end(); ++sdi) { globalreg->kisnetserver->SendToAll(proto_ref_bssidsrc, (void *) sdi->second); } for (map::const_iterator ai = net->arb_tag_map.begin(); ai != net->arb_tag_map.end(); ++ai) { nettag_struct s; s.bssid = net->bssid; s.mi = ai; globalreg->kisnetserver->SendToAll(proto_ref_nettag, (void *) &s); } /* Reset the frag, retry, and packet counters */ net->fragments = 0; net->retries = 0; net->new_packets = 0; net->dirty = 0; } for (unsigned int x = 0; x < dirty_cli_vec.size(); x++) { tracked_client *cli = dirty_cli_vec[x]; int filtered = 0; if (cli->type == client_remove) continue; if (netcli_filter->RunFilter(cli->netptr->bssid, mac_addr(0), mac_addr(0))) continue; map::iterator asi; for (asi = cli->netptr->ssid_map.begin(); asi != cli->netptr->ssid_map.end(); ++asi) { if (netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } if (filtered) continue; globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_CLIENT), (void *) cli); for (map::iterator sdi = cli->source_map.begin(); sdi != cli->source_map.end(); ++sdi) { globalreg->kisnetserver->SendToAll(proto_ref_clisrc, (void *) sdi->second); } for (asi = cli->ssid_map.begin(); asi != cli->ssid_map.end(); ++asi) { if (asi->second->dirty == 0) continue; globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_SSID), (void *) asi->second); asi->second->dirty = 0; } for (map::const_iterator ai = cli->arb_tag_map.begin(); ai != cli->arb_tag_map.end(); ++ai) { nettag_struct s; s.bssid = cli->bssid; s.mac = cli->mac; s.mi = ai; globalreg->kisnetserver->SendToAll(proto_ref_clitag, (void *) &s); } // Reset the frag, retry, and packet counts cli->fragments = 0; cli->retries = 0; cli->new_packets = 0; cli->dirty = 0; } // Empty the vectors dirty_net_vec.clear(); dirty_cli_vec.clear(); num_packetdelta = 0; return 1; } int Netracker::netracker_chain_handler(kis_packet *in_pack) { tracked_network *net = NULL; tracked_client *cli = NULL; int newnetwork = 0; int newclient = 0; char status[STATUS_MAX]; Packinfo_Sig_Combo *sc = NULL; // Fetch the info from the packet chain data kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); kis_gps_packinfo *gpsinfo = (kis_gps_packinfo *) in_pack->fetch(_PCM(PACK_COMP_GPS)); kis_layer1_packinfo *l1info = (kis_layer1_packinfo *) in_pack->fetch(_PCM(PACK_COMP_RADIODATA)); // No 802.11 info, we don't handle it. if (packinfo == NULL) { return 0; } num_packets++; num_packetdelta++; // Not an 802.11 frame type we known how to track, we'll just skip // it, too if (packinfo->corrupt || packinfo->type == packet_noise || in_pack->error || packinfo->type == packet_unknown || packinfo->subtype == packet_sub_unknown) { num_errorpackets++; return 0; } // Phy packets have no BSSID information so there's nothing else // we can do if (packinfo->type == packet_phy) { num_llcpackets++; return 1; } // Compare against the filter and return w/out making a network record or // anything if we're due to be excluded anyhow. This also keeps datatracker // handlers from processing since they won't find a network reference if (track_filter->RunFilter(packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac)) { num_filterpackets++; return 0; } // Look to see if we already track this bssid and grab it if we do track_iter triter = tracked_map.find(packinfo->bssid_mac); if (triter != tracked_map.end()) { net = triter->second; } // Try to map probe reqs into the network they really belong in, if we // track probes, and we don't already have a network for them if (track_probenets && net == NULL && packinfo->type == packet_management && packinfo->subtype == packet_sub_probe_req) { if (probe_assoc_map.find(packinfo->bssid_mac) != probe_assoc_map.end()) { net = probe_assoc_map[packinfo->bssid_mac]; } } // Spawn a new network record if (net == NULL) { // Constructor will make our network record clear net = new Netracker::tracked_network; // Cached IP data if (bssid_ip_map.find(packinfo->bssid_mac) != bssid_ip_map.end()) { net->guess_ipdata = bssid_ip_map[packinfo->bssid_mac]; } net->bssid = packinfo->bssid_mac; // Load persistent tags vector tfl = tag_conf->FetchOptVec(net->bssid.Mac2String()); vector tflp; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; net->arb_tag_map[tflp[0].word] = tflp[1].word; } if (globalreg->manufdb != NULL) net->manuf = globalreg->manufdb->LookupOUI(net->bssid); if (packinfo->type == packet_management && packinfo->subtype == packet_sub_probe_req) { net->type = network_probe; } else if (packinfo->distrib == distrib_adhoc) { net->type = network_adhoc; } else if (packinfo->type == packet_data) { net->type = network_data; } else { net->type = network_ap; } // FIXME: Add turbocell net->first_time = globalreg->timestamp.tv_sec; net->bss_timestamp = packinfo->timestamp; // Learn it tracked_map[net->bssid] = net; newnetwork = 1; // Everything else needs to change with new frames so we fill it in // outside of the new network code, obviously } else { if (packinfo->distrib == distrib_adhoc && net->type == network_ap) { if (globalreg->alertracker->PotentialAlert(alert_adhoc_ref)) { string al = "Network BSSID " + net->bssid.Mac2String() + " advertised as AP network, now advertising as Ad-Hoc IBSS, " "which may indicate AP spoofing/impersonation"; globalreg->alertracker->RaiseAlert(alert_adhoc_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, al); } } else if (packinfo->type == packet_management && packinfo->ess && net->type == network_data) { // Management frames from an AP on a data-only network turn it into // an AP network net->type = network_ap; } else if (packinfo->distrib == distrib_adhoc) { net->type = network_adhoc; } } // Handle client creation inside this network - we already made a net // so even if it's client-only data traffic we have a valid net ptr client_iter clitr; if ((clitr = net->client_map.find(packinfo->source_mac)) == net->client_map.end()) { // Make a new client and fill it in cli = new tracked_client; cli->first_time = globalreg->timestamp.tv_sec; cli->mac = packinfo->source_mac; cli->bssid = net->bssid; // Load persistent tags vector tfl = tag_conf->FetchOptVec(cli->bssid.Mac2String() + ":" + cli->bssid.Mac2String()); vector tflp; for (unsigned int x = 0; x < tfl.size(); x++) { tflp = NetStrTokenize(tfl[x], ","); if (tflp.size() != 2) continue; net->arb_tag_map[tflp[0].word] = tflp[1].word; } if (globalreg->manufdb != NULL) cli->manuf = globalreg->manufdb->LookupOUI(cli->mac); // Set the distribution type if (packinfo->distrib == distrib_from || (packinfo->type == packet_management && packinfo->subtype == packet_sub_beacon)) cli->type = client_fromds; else if (packinfo->distrib == distrib_to) cli->type = client_tods; else if (packinfo->distrib == distrib_inter) cli->type = client_interds; else if (packinfo->distrib == distrib_adhoc) cli->type = client_adhoc; else cli->type = client_unknown; // Pointer to parent net, just in case cli->netptr = net; // Log it in the simple map net->client_map[cli->mac] = cli; newclient = 1; } else { cli = clitr->second; // Process the type to indicate established clients if ((packinfo->distrib == distrib_to && cli->type == client_fromds) || (packinfo->distrib == distrib_from && cli->type == client_tods)) cli->type = client_established; else if (packinfo->distrib == distrib_inter) cli->type = client_interds; else if (packinfo->distrib == distrib_adhoc) cli->type = client_adhoc; } // Link it to the packet for future chain elements kis_netracker_netinfo *netpackinfo = new kis_netracker_netinfo; netpackinfo->netref = net; in_pack->insert(_PCM(PACK_COMP_TRACKERNET), netpackinfo); kis_netracker_cliinfo *clipackinfo = new kis_netracker_cliinfo; clipackinfo->cliref = cli; in_pack->insert(_PCM(PACK_COMP_TRACKERCLIENT), clipackinfo); // Update the time net->last_time = globalreg->timestamp.tv_sec; cli->last_time = globalreg->timestamp.tv_sec; // Dirty the network if (net->dirty == 0) { net->dirty = 1; dirty_net_vec.push_back(net); } if (gpsinfo != NULL) { net->gpsdata += gpsinfo; cli->gpsdata += gpsinfo; } // Make an info pair and add it to our signaling layer if (l1info != NULL) { sc = new Packinfo_Sig_Combo(l1info, gpsinfo); net->snrdata += *sc; cli->snrdata += *sc; } // Add the source to the network record of who has seen us and when kis_ref_capsource *capsource = (kis_ref_capsource *) in_pack->fetch(_PCM(PACK_COMP_KISCAPSRC)); if (capsource != NULL && capsource->ref_source != NULL) { map::iterator sdi; if ((sdi = net->source_map.find(capsource->ref_source->FetchUUID())) != net->source_map.end()) { sdi->second->last_seen = globalreg->timestamp.tv_sec; sdi->second->num_packets++; if (sc != NULL) sdi->second->snrdata += *sc; } else { source_data *sd = new source_data; sd->source_uuid = capsource->ref_source->FetchUUID(); sd->last_seen = globalreg->timestamp.tv_sec; sd->num_packets = 1; sd->bssid = net->bssid; if (sc != NULL) sd->snrdata += *sc; net->source_map[sd->source_uuid] = sd; } if ((sdi = cli->source_map.find(capsource->ref_source->FetchUUID())) != cli->source_map.end()) { sdi->second->last_seen = globalreg->timestamp.tv_sec; sdi->second->num_packets++; if (sc != NULL) sdi->second->snrdata += *sc; } else { source_data *sd = new source_data; sd->source_uuid = capsource->ref_source->FetchUUID(); sd->last_seen = globalreg->timestamp.tv_sec; sd->num_packets = 1; sd->bssid = net->bssid; sd->mac = cli->mac; if (sc != NULL) sd->snrdata += *sc; cli->source_map[sd->source_uuid] = sd; } } // Add to the LLC count if (packinfo->type == packet_management) { num_llcpackets++; } // Add to the frequency tracking, inefficient search but it's a small set if (l1info != NULL) { if (net->freq_mhz_map.find(l1info->freq_mhz) != net->freq_mhz_map.end()) net->freq_mhz_map[l1info->freq_mhz]++; else net->freq_mhz_map[l1info->freq_mhz] = 1; if (cli->freq_mhz_map.find(l1info->freq_mhz) != cli->freq_mhz_map.end()) cli->freq_mhz_map[l1info->freq_mhz]++; else cli->freq_mhz_map[l1info->freq_mhz] = 1; } // Extract info from probe request frames if its a probe network if (packinfo->type == packet_management && packinfo->subtype == packet_sub_probe_req) { // Build the SSID block checksum ostringstream ssid_st; // Combine some fields into a string ssid_st << packinfo->ssid << packinfo->ssid_len; packinfo->ssid_csum = Adler32Checksum(ssid_st.str().c_str(), ssid_st.str().length()); map::iterator ssidi = net->ssid_map.find(packinfo->ssid_csum); Netracker::adv_ssid_data *adssid; if (ssidi == net->ssid_map.end()) { adssid = BuildAdvSSID(packinfo->ssid_csum, packinfo, in_pack); adssid->type = ssid_probereq; cli->ssid_map[packinfo->ssid_csum] = adssid; } else { adssid = ssidi->second; } // Alert on crypto change if (adssid->cryptset != packinfo->cryptset && adssid->cryptset != 0 && globalreg->alertracker->PotentialAlert(alert_wepflap_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " changed advertised SSID '" + packinfo->ssid + "' encryption "; if (packinfo->cryptset == 0) outs << "to no encryption when it was previous advertised, an " "impersonation attack may be underway"; else if (packinfo->cryptset < adssid->cryptset) outs << "to a weaker encryption set than previously " "advertised, which may indicate an attack"; else outs << "a different encryption set than previous advertised"; globalreg->alertracker->RaiseAlert(alert_wepflap_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } adssid->cryptset = packinfo->cryptset; adssid->last_time = globalreg->timestamp.tv_sec; adssid->packets++; adssid->maxrate = packinfo->maxrate; adssid->dirty = 1; } // Extract info from beacon frames, they're the only ones we trust to // give us good info... if (packinfo->type == packet_management && packinfo->subtype == packet_sub_beacon) { // If we're a new network, look up cached and add us to the ssid map if (newnetwork) { string cached; if ((cached = ssid_conf->FetchOpt(packinfo->bssid_mac.Mac2String())) != "") { // If we have some indication of the length thanks to nulled-out // bytes, don't import a cache with a different length, otherwise // import the cache and flag that we're from a file if ((packinfo->ssid_len != 0 && packinfo->ssid_len == (int) cached.length()) || packinfo->ssid_len == 0) { adv_ssid_data *cd = new adv_ssid_data; cd->type = ssid_file; cd->ssid = cached; net->ssid_map[0] = cd; } } } // Build the SSID block checksum ostringstream ssid_st; // Combine some fields into a string ssid_st << packinfo->ssid << packinfo->ssid_len; packinfo->ssid_csum = Adler32Checksum(ssid_st.str().c_str(), ssid_st.str().length()); map::iterator ssidi = net->ssid_map.find(packinfo->ssid_csum); Netracker::adv_ssid_data *adssid; if (ssidi == net->ssid_map.end()) { adssid = BuildAdvSSID(packinfo->ssid_csum, packinfo, in_pack); adssid->type = ssid_beacon; net->ssid_map[packinfo->ssid_csum] = adssid; } else { adssid = ssidi->second; } adssid->last_time = globalreg->timestamp.tv_sec; adssid->packets++; adssid->beacons++; adssid->dirty = 1; if (alert_airjackssid_ref >= 0 && packinfo->ssid == "AirJack" && globalreg->alertracker->PotentialAlert(alert_airjackssid_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " broadcasting SSID 'AirJack' which implies an attempt " "to disrupt networks"; globalreg->alertracker->RaiseAlert(alert_airjackssid_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } if (packinfo->cryptset == 0) { if (adssid->cryptset && alert_wepflap_ref && globalreg->alertracker->PotentialAlert(alert_wepflap_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " stopped advertising encryption"; globalreg->alertracker->RaiseAlert(alert_wepflap_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } } // Copy the crypto data adssid->cryptset = packinfo->cryptset; // Fire off an alert if the channel changes if (alert_chan_ref >= 0 && newnetwork == 0 && net->channel != 0 && packinfo->channel != 0 && net->channel != packinfo->channel && globalreg->alertracker->PotentialAlert(alert_chan_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " changed " "channel from " << net->channel << " to " << packinfo->channel; globalreg->alertracker->RaiseAlert(alert_chan_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } if (packinfo->channel != 0) { // Inherit the channel from the beacon net->channel = packinfo->channel; cli->channel = packinfo->channel; } else if (l1info != NULL) { // Otherwise inherit it from the radio layer. Arguably this could // lie for 2.4ghz stuff, but a 2.4ghz beacon should always have // the channel in it. 5ghz (and presumably 4.x ghz) networks don't // carry the beacon net->channel = FreqToChan(l1info->freq_mhz); cli->channel = net->channel; } // Copy the dot11d data adssid->dot11d_country = packinfo->dot11d_country; adssid->dot11d_vec = packinfo->dot11d_vec; } // Catch probe responses, handle adding probe resp SSIDs if (packinfo->type == packet_management && packinfo->subtype == packet_sub_probe_resp) { // Build the SSID block checksum ostringstream ssid_st; // Combine some fields into a string ssid_st << packinfo->ssid << packinfo->ssid_len; packinfo->ssid_csum = Adler32Checksum(ssid_st.str().c_str(), ssid_st.str().length()); map::iterator ssidi = net->ssid_map.find(packinfo->ssid_csum); Netracker::adv_ssid_data *adssid; if (ssidi == net->ssid_map.end()) { adssid = BuildAdvSSID(packinfo->ssid_csum, packinfo, in_pack); adssid->type = ssid_proberesp; net->ssid_map[packinfo->ssid_csum] = adssid; } else { adssid = ssidi->second; } // Alert on crypto change if (packinfo->cryptset == 0 && adssid->cryptset != 0 && globalreg->alertracker->PotentialAlert(alert_wepflap_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " responding to SSID '" + packinfo->ssid + "' with " "no encryption when it was previously advertised as " "encrypted, an impersonation attack may be underway"; globalreg->alertracker->RaiseAlert(alert_wepflap_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } adssid->cryptset |= packinfo->cryptset; adssid->last_time = globalreg->timestamp.tv_sec; adssid->packets++; adssid->dirty = 1; } // Fire an alert on a disconnect/deauth broadcast if (alert_bcastdcon_ref >= 0 && packinfo->type == packet_management && (packinfo->subtype == packet_sub_disassociation || packinfo->subtype == packet_sub_deauthentication) && packinfo->dest_mac == bcast_mac && globalreg->alertracker->PotentialAlert(alert_bcastdcon_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " broadcast " "deauthenticate/disassociation of all clients, possible DoS"; globalreg->alertracker->RaiseAlert(alert_bcastdcon_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } if (packinfo->type == packet_management || packinfo->type == packet_phy) { net->llc_packets++; cli->llc_packets++; } else if (packinfo->type == packet_data) { num_datapackets++; net->data_packets++; cli->data_packets++; if (packinfo->cryptset) { num_cryptpackets++; net->crypt_packets++; cli->crypt_packets++; } // Handle data sizes net->datasize += packinfo->datasize; cli->datasize += packinfo->datasize; } // Increment per-unit rates net->new_packets++; cli->new_packets++; // Handle fragment and retry values if (packinfo->fragmented) { net->fragments++; cli->fragments++; } if (packinfo->retry) { net->retries++; cli->retries++; } int net_filtered = 0; if (newnetwork) { string nettype; if (net->type == network_ap) { nettype = "managed"; } else if (net->type == network_adhoc) { nettype = "ad-hoc"; } else if (net->type == network_probe) { nettype = "probe"; } else if (net->type == network_turbocell) { nettype = "turbocell"; } else if (net->type == network_data) { nettype = "data"; } // Use the packinfo field here to spew out info about the network, // since we don't want to have to find the advssid data related string ssid; if (packinfo->ssid_len == 0) { if (net->type == network_probe) { ssid = ""; } else if (net->type == network_data) { ssid = ""; } else { ssid = ""; } } else { ssid = packinfo->ssid; } snprintf(status, STATUS_MAX, "Detected new %s network \"%s\", BSSID %s, " "encryption %s, channel %d, %2.2f mbit", nettype.c_str(), ssid.c_str(), net->bssid.Mac2String().c_str(), packinfo->cryptset ? "yes" : "no", net->channel, packinfo->maxrate); _MSG(status, MSGFLAG_INFO); // Check filtering and send BSSID int filtered = 0; map::iterator asi; for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (netcli_filter->RunPcreFilter(asi->second->ssid)) { filtered = 1; break; } } net_filtered = filtered; // Send the BSSID and all SSIDs: If it's a new BSSID, by default, // all SSIDs are new if (filtered == 0) { globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_BSSID), (void *) net); for (asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_SSID), (void *) asi->second); } } } // Don't send clients for filtered nets if (newclient && net_filtered == 0) { // Send the BSSID and all SSIDs: If it's a new BSSID, by default, // all SSIDs are new map::iterator asi; for (asi = cli->ssid_map.begin(); asi != cli->ssid_map.end(); ++asi) { globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_SSID), (void *) asi->second); } } if (net->dirty == 0) { net->dirty = 1; dirty_net_vec.push_back(net); } if (cli->dirty == 0) { cli->dirty = 1; dirty_cli_vec.push_back(cli); } // TODO/FIXME: // "Smart" vs. "Purely accurate" adhoc handling return 1; } int Netracker::datatracker_chain_handler(kis_packet *in_pack) { // Fetch the info from the packet chain data kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); // No 802.11 info, we don't handle it. if (packinfo == NULL) { return 0; } // Not an 802.11 frame type we known how to track, we'll just skip // it, too if (packinfo->corrupt || packinfo->type != packet_data) { return 0; } kis_data_packinfo *datainfo = (kis_data_packinfo *) in_pack->fetch(_PCM(PACK_COMP_BASICDATA)); // No data info? We can't handle it if (datainfo == NULL) { return 0; } // Make sure we got a network tracked_network *net; kis_netracker_netinfo *netpackinfo = (kis_netracker_netinfo *) in_pack->fetch(_PCM(PACK_COMP_TRACKERNET)); // No network? Can't handle this either. if (netpackinfo == NULL) { return 0; } net = netpackinfo->netref; // Make sure we got a client, too tracked_client *cli; kis_netracker_cliinfo *clipackinfo = (kis_netracker_cliinfo *) in_pack->fetch(_PCM(PACK_COMP_TRACKERCLIENT)); // No network? Can't handle this either. if (clipackinfo == NULL) { return 0; } cli = clipackinfo->cliref; kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } } // Track decryption if (packinfo->decrypted) { net->decrypted++; // printf("debug - decrypted packet, net %s %d\n", net->bssid.Mac2String().c_str(), net->decrypted); } // Apply the network-level stuff if (packinfo->source_mac == net->bssid) { // Things that come from the MAC of the AP carry special weight. // CDP gets copied over so that we can figure out where this AP is // (maybe) net->cdp_dev_id = datainfo->cdp_dev_id; net->cdp_port_id = datainfo->cdp_port_id; cli->cdp_dev_id = datainfo->cdp_dev_id; cli->cdp_port_id = datainfo->cdp_port_id; } // Apply the data layer crypt info net->data_cryptset |= packinfo->cryptset; cli->data_cryptset |= packinfo->cryptset; // Apply the DHCP discovery on the client if (datainfo->proto == proto_dhcp_discover) { if (cli->dhcp_host != datainfo->discover_host && cli->dhcp_host != "" && globalreg->alertracker->PotentialAlert(alert_dhcpname_ref)) { string al = "Network BSSID " + net->bssid.Mac2String() + " client " + cli->mac.Mac2String() + " changed advertised hostname in DHCP " + "from '" + cli->dhcp_host + "' to '" + datainfo->discover_host + "' " + "which may indicate client spoofing/impersonation"; globalreg->alertracker->RaiseAlert(alert_dhcpname_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, al); } if (cli->dhcp_vendor != datainfo->discover_vendor && cli->dhcp_vendor != "" && globalreg->alertracker->PotentialAlert(alert_dhcpos_ref)) { string al = "Network BSSID " + net->bssid.Mac2String() + " client " + cli->mac.Mac2String() + " changed advertised vendor in DHCP " + "from '" + cli->dhcp_vendor + "' to '" + datainfo->discover_vendor + "' which may indicate client spoofing/impersonation"; globalreg->alertracker->RaiseAlert(alert_dhcpos_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, al); } cli->dhcp_host = datainfo->discover_host; cli->dhcp_vendor = datainfo->discover_vendor; } // Start comparing IP stuff and move it into the network. We don't // trust IPs coming from the the AP itself UNLESS they're DHCP-Offers because // an AP in router mode tends to replicate in internet addresses and confuse // things all over the place. int ipdata_dirty = 0; if ((packinfo->source_mac == net->bssid && datainfo->proto == proto_dhcp_offer) || packinfo->source_mac != net->bssid) { if (datainfo->proto == proto_dhcp_offer) { // DHCP Offers are about the most complete and authoritative IP info we // can get, so we just overwrite our network knowledge with it. // First, check and see if we're going to make noise about this being // a conflicting DHCP offer... since DHCP is the "best" type of address, // if we've seen an offer before, it will be this address. in_addr ip_calced_range; ip_calced_range.s_addr = (datainfo->ip_dest_addr.s_addr & datainfo->ip_netmask_addr.s_addr); if (alert_dhcpcon_ref >= 0 && net->guess_ipdata.ip_type == ipdata_dhcp && ip_calced_range.s_addr != net->guess_ipdata.ip_addr_block.s_addr && ip_calced_range.s_addr != 0 && net->guess_ipdata.ip_addr_block.s_addr != 0 && globalreg->alertracker->PotentialAlert(alert_dhcpcon_ref)) { ostringstream outs; outs << "Network BSSID " << net->bssid.Mac2String() << " got " "conflicting DHCP offer from " << packinfo->source_mac.Mac2String() << " of " << string(inet_ntoa(net->guess_ipdata.ip_addr_block)) << " previously " << string(inet_ntoa(ip_calced_range)); globalreg->alertracker->RaiseAlert(alert_dhcpcon_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, outs.str()); } // Copy it into our network IP data net->guess_ipdata.ip_type = ipdata_dhcp; // IP range goes straight in masked w/ offered netmask net->guess_ipdata.ip_addr_block.s_addr = ip_calced_range.s_addr; net->guess_ipdata.ip_netmask.s_addr = datainfo->ip_netmask_addr.s_addr; net->guess_ipdata.ip_gateway.s_addr = datainfo->ip_gateway_addr.s_addr; if (net->dirty == 0) { net->dirty = 1; dirty_net_vec.push_back(net); } // Copy it into our client ip data too cli->guess_ipdata.ip_type = ipdata_dhcp; cli->guess_ipdata.ip_addr_block.s_addr = ip_calced_range.s_addr; cli->guess_ipdata.ip_netmask.s_addr = datainfo->ip_netmask_addr.s_addr; cli->guess_ipdata.ip_gateway.s_addr = datainfo->ip_gateway_addr.s_addr; if (cli->dirty == 0) { cli->dirty = 1; dirty_cli_vec.push_back(cli); } ipdata_dirty = 1; } else if (datainfo->proto == proto_arp) { // Second most trusted: ARP. ARP only occurs within the IP subnet, // which should be tied to the physical broadcast domain, which should // be a good gauge of our network range if (cli->guess_ipdata.ip_type <= ipdata_arp) { cli->guess_ipdata.ip_type = ipdata_arp; cli->guess_ipdata.ip_addr_block.s_addr = datainfo->ip_source_addr.s_addr; if (cli->dirty == 0) { cli->dirty = 1; dirty_cli_vec.push_back(cli); } ipdata_dirty = 1; } } else if (datainfo->proto == proto_udp || datainfo->proto == proto_tcp) { // Third most trusted: TCP and UDP... update the client if (cli->guess_ipdata.ip_type <= ipdata_udptcp) { cli->guess_ipdata.ip_type = ipdata_udptcp; if (packinfo->distrib == distrib_from) { // Coming from the distribution to a client, we probably care // about the destination since it's inside our network cli->guess_ipdata.ip_addr_block.s_addr = datainfo->ip_dest_addr.s_addr; } else { // Coming from a client, we're more likely to care about the // source. Let this drop into a generic else since we // might as well use the source addr for anything else. Other // distrib types don't give us enough of a clue so source is // as good as anything cli->guess_ipdata.ip_addr_block.s_addr = datainfo->ip_source_addr.s_addr; } // Zero the rest of the stuff cli->guess_ipdata.ip_netmask.s_addr = 0; cli->guess_ipdata.ip_gateway.s_addr = 0; if (cli->dirty == 0) { cli->dirty = 1; dirty_cli_vec.push_back(cli); } ipdata_dirty = 1; } } // Recalculate the network IP characteristics if it's not DHCP if (ipdata_dirty && net->guess_ipdata.ip_type != ipdata_dhcp) { in_addr min_addr, max_addr, mask_addr; uint32_t maskbits = ~0 & ~(1 << 0); min_addr.s_addr = ~0; max_addr.s_addr = 0; mask_addr.s_addr = 0; for (client_iter i = net->client_map.begin(); i != net->client_map.end(); ++i) { uint32_t ha; // Immediately inherit DHCP data masked by the netmask if (i->second->guess_ipdata.ip_type == ipdata_dhcp) { net->guess_ipdata = i->second->guess_ipdata; net->guess_ipdata.ip_addr_block.s_addr &= net->guess_ipdata.ip_netmask.s_addr; _MSG("Found IP range " + string(inet_ntoa(net->guess_ipdata.ip_addr_block)) + "/" + string(inet_ntoa(net->guess_ipdata.ip_netmask)) + " via DHCP for network " + net->bssid.Mac2String(), MSGFLAG_INFO); goto end_ip_decode; break; } // fprintf(stderr, "debug - client ip %s\n", inet_ntoa(i->second->guess_ipdata.ip_addr_block)); ha = ntohl(i->second->guess_ipdata.ip_addr_block.s_addr); if (ha == 0) continue; if (ha < min_addr.s_addr) min_addr.s_addr = ha; if (ha > max_addr.s_addr) max_addr.s_addr = ha; } min_addr.s_addr = htonl(min_addr.s_addr); max_addr.s_addr = htonl(max_addr.s_addr); for (int x = 1; x < 31; x++) { mask_addr.s_addr = htonl(maskbits); if ((mask_addr.s_addr & min_addr.s_addr) == (mask_addr.s_addr & max_addr.s_addr)) { break; } maskbits &= ~(1 << x); } in_addr combo; combo.s_addr = (min_addr.s_addr & mask_addr.s_addr); // fprintf(stderr, "debug - %s min %s max %s mask %s new %s old %s\n", net->bssid.Mac2String().c_str(), strdup(inet_ntoa(min_addr)), strdup(inet_ntoa(max_addr)), strdup(inet_ntoa(mask_addr)), strdup(inet_ntoa(combo)), strdup(inet_ntoa(net->guess_ipdata.ip_addr_block))); if ((min_addr.s_addr & mask_addr.s_addr) != net->guess_ipdata.ip_addr_block.s_addr) { net->guess_ipdata.ip_addr_block.s_addr = (min_addr.s_addr & mask_addr.s_addr); net->guess_ipdata.ip_netmask = mask_addr; net->guess_ipdata.ip_gateway.s_addr = 0; if (net->guess_ipdata.ip_type != ipdata_group) { net->guess_ipdata.ip_type = ipdata_group; _MSG("Found IP range " + string(inet_ntoa(net->guess_ipdata.ip_addr_block)) + "/" + string(inet_ntoa(net->guess_ipdata.ip_netmask)) + " for network " + net->bssid.Mac2String(), MSGFLAG_INFO); } } } // ipdata dirty } // ip considered end_ip_decode: return 1; } int Netracker::FetchNumNetworks() { return tracked_map.size(); } int Netracker::FetchNumClients() { return client_mini_map.size(); } int Netracker::FetchNumPackets() { return num_packets; } int Netracker::FetchNumDatapackets() { return num_datapackets; } int Netracker::FetchNumCryptpackets() { return num_cryptpackets; } int Netracker::FetchNumErrorpackets() { return num_errorpackets; } int Netracker::FetchNumLLCpackets() { return num_llcpackets; } int Netracker::FetchNumFiltered() { return num_filterpackets; } int Netracker::FetchPacketRate() { return num_packetdelta; } const map Netracker::FetchTrackedNets() { return tracked_map; } const map Netracker::FetchProbeNets() { return probe_assoc_map; } Netracker::adv_ssid_data *Netracker::BuildAdvSSID(uint32_t ssid_csum, kis_ieee80211_packinfo *packinfo, kis_packet *in_pack) { Netracker::adv_ssid_data *adssid; Netracker::tracked_network *net = NULL; adssid = new Netracker::adv_ssid_data; adssid->checksum = ssid_csum; adssid->mac = packinfo->bssid_mac; adssid->ssid = string(packinfo->ssid); if (packinfo->ssid_len == 0 || packinfo->ssid_blank) { adssid->ssid_cloaked = 1; } adssid->beacon_info = string(packinfo->beacon_info); adssid->cryptset = packinfo->cryptset; adssid->first_time = globalreg->timestamp.tv_sec; adssid->maxrate = packinfo->maxrate; adssid->beaconrate = Ieee80211Interval2NSecs(packinfo->beacon_interval); adssid->packets = 0; // If it's a probe response record it in the SSID cache, we only record // one per BSSID for now and only if we have a cloaked SSID on this record. // While we're at it, also figure out if we're responding for SSIDs we've never // been advertising (in a non-cloaked way), that's probably not a good // thing. if (packinfo->type == packet_management && packinfo->subtype == packet_sub_probe_resp && (packinfo->ssid_len || packinfo->ssid_blank == 0)) { if (tracked_map.find(packinfo->bssid_mac) != tracked_map.end()) { net = tracked_map[packinfo->bssid_mac]; for (map::iterator asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { // Catch beacon, cloaked situation if (asi->second->type == ssid_beacon && asi->second->ssid_cloaked) { // Remember the revealed SSID ssid_conf->SetOpt(packinfo->bssid_mac.Mac2String(), packinfo->ssid, globalreg->timestamp.tv_sec); } } } } if (packinfo->type == packet_management && (packinfo->subtype == packet_sub_probe_resp || packinfo->subtype == packet_sub_beacon)) { // Run it through the AP spoof protection system for (unsigned int x = 0; x < apspoof_vec.size(); x++) { // Shortcut to checking the mac address first, if it's one we // have then we don't have to do the expensive operation of pcre or // string matching if (apspoof_vec[x]->allow_mac_map.find(packinfo->source_mac) != apspoof_vec[x]->allow_mac_map.end()) { continue; } int match = 0, matched = 0; string match_type; #ifdef HAVE_LIBPCRE if (apspoof_vec[x]->ssid_re != NULL) { int ovector[128]; match = (pcre_exec(apspoof_vec[x]->ssid_re, apspoof_vec[x]->ssid_study, packinfo->ssid.c_str(), packinfo->ssid.length(), 0, 0, ovector, 128) >= 0); match_type = "regular expression"; matched = 1; } #endif if (matched == 0) { match = (apspoof_vec[x]->ssid == packinfo->ssid); match_type = "SSID"; matched = 1; } if (match && globalreg->alertracker->PotentialAlert(alert_adhoc_ref)) { string ntype = packinfo->subtype == packet_sub_beacon ? string("advertising") : string("responding for"); string al = "Unauthorized device (" + packinfo->source_mac.Mac2String() + string(") ") + ntype + " for SSID '" + packinfo->ssid + "', matching APSPOOF " "rule " + apspoof_vec[x]->name + string(" with ") + match_type + string(" which may indicate spoofing or impersonation."); globalreg->alertracker->RaiseAlert(alert_ssidmatch_ref, in_pack, packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac, packinfo->other_mac, packinfo->channel, al); break; } } } return adssid; } kismet-2013-03-R1b/ipc_remote.h0000664000175000017500000001773212124602454015764 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * IPC remote * * Handles commands that can't/won't/shouldn't be handled by the main * Kismet process. The primary example of this is the root-level * control process used by the unprivileged Kismet to drive channel set * events. * * All commands and pointers MUST be set up BEFORE the IPC fork. * * An alternate child command can be specified. It MUST take as the first argument * an integer indicating the file descriptor number of the IPC pipe, and it MUST * understand the IPC protocol over this descriptor. * * The child binary must call SetChildExecMode(argc, argv) prior to filling in the * registered protocols, then call SpawnIPC() to kickstart processing. * * On some platforms (linux) a framework for passing file descriptors is available * as well via named unix sockets. Caller must send IPC to open early in the * initialization process and then try to open the socket locally. * */ #ifndef __IPC_REMOTE_H__ #define __IPC_REMOTE_H__ #include "config.h" #include #include #include #include #include #include #include #ifdef SYS_LINUX #include #include #include #include #include #include #include #endif #include #include #include "globalregistry.h" #include "pollable.h" #include "messagebus.h" #define IPC_CMD_PARMS GlobalRegistry *globalreg, const void *data, int len, \ const void *auxptr, int parent typedef int (*IPCmdCallback)(IPC_CMD_PARMS); // Builtin command IDs we force (added before assign, so start at 1) #define DIE_CMD_ID 1 #define MSG_CMD_ID 2 #define SYNC_CMD_ID 3 #define LAST_BUILTIN_CMD_ID 4 // Message client to redirect messages over the IPC link class IPC_MessageClient : public MessageClient { public: IPC_MessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { }; virtual ~IPC_MessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; // Message frame to go over IPC struct ipc_msgbus_pass { uint32_t msg_flags; uint32_t msg_len; // Redundant but simpler to read char msg[0]; }; // Super-generic IPC packet. This never sees outside of a unix dgram // frame, so we don't have to armor or protect it. Just a handy method for // tossing simple chunks of data. Commands are responsible for filling in // reasonable structs for *data struct ipc_packet { uint32_t sentinel; uint32_t ipc_cmdnum; uint32_t data_len; uint8_t ipc_ack; uint8_t data[0]; }; // Sync frame the link names and numbers with spawned ipc children struct ipc_sync { uint32_t ipc_cmdnum; uint8_t name[32]; }; // IPC sentinel const uint32_t IPCRemoteSentinel = 0xDECAFBAD; class IPCRemote : public Pollable { public: IPCRemote(); IPCRemote(GlobalRegistry *in_globalreg, string procname); virtual ~IPCRemote(); virtual void SetChildCmd(string in_cmd) { child_cmd = in_cmd; } // Start execution as the child and get the IPC descriptor from the // command line options passed from the IPC spawn virtual int SetChildExecMode(int argc, char *argv[]); virtual int SpawnIPC(); // Call after registering all services in a childexec, which don't have // to be registered before spawn virtual int SyncIPC(); // Get a shutdown virtual void CatchSigChild(int status) { exit_errno = WEXITSTATUS(status); ShutdownIPC(NULL); } // Shutdown takes an optional final packet to send before sending the // death packet virtual int ShutdownIPC(ipc_packet *pack); // IPC commands are integers, which means we get away without having to care // at all if they duplicate commands or whatever, so we don't even really // care about unique callbacks. Makes life easy for us. virtual int RegisterIPCCmd(IPCmdCallback in_callback, IPCmdCallback discard_ackback, void *in_aux, string name); virtual int SyncIPCCmd(ipc_sync *data); // Kick a command across (either direction) virtual int SendIPC(ipc_packet *pack); // Is the IPC ready for more commands? This would mean that the last // command was ack'd and that we don't have any queued up to still send. // Some uses might want to defer sending a command until the IPC is // settled. virtual int FetchReadyState(); pid_t FetchSpawnPid() { return ipc_pid; } int FetchErrno() { return exit_errno; } virtual int FetchIPCSynced() { return ipc_synced; } // Pollable system virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); struct ipc_cmd_rec { void *auxptr; IPCmdCallback callback; string name; int id; }; protected: // Child process that never returns virtual void IPC_Child_Loop(); // Internal die functions virtual void IPCDie(); virtual int CheckPidVec(); GlobalRegistry *globalreg; // This isn't a ringbuf since it's dgram single-tx frames list cmd_buf; // Name of the process we'll use in the child string procname; int next_cmdid; // Pair used to talk to the Other Half int sockpair[2]; // PID of the child process pid_t ipc_pid; // Have we spawned a subproc? Blow up on setup commands if // we have. int ipc_spawned; map ipc_cmd_map; // Normally this would be a vec but it's a lot cheaper for ram and code size // to re-use the template map ipc_sync_map; // Cmd to run instead of a copy of ourself. string child_cmd; int child_exec_mode; friend class IPC_MessageClient; friend int ipc_die_callback(IPC_CMD_PARMS); friend int ipc_ack_callback(IPC_CMD_PARMS); // Reason we're exiting int exit_errno; // Have we been synced? (child) int ipc_synced; }; // Special IPCremote class for root control binary, used by IPC remote and // tuntap control, among others class RootIPCRemote : public IPCRemote { public: RootIPCRemote() { IPCRemote(); } RootIPCRemote(GlobalRegistry *in_globalreg, string procname); virtual ~RootIPCRemote() { IPCDie(); } virtual void CatchSigChild(int status) { if (!globalreg->spindown) { _MSG("Suid-root control binary failed: " + string(strerror(WEXITSTATUS(status))), MSGFLAG_FATAL); } // globalreg->fatal_condition = 1; IPCRemote::CatchSigChild(status); } virtual int OpenFDPassSock(); // Send a descriptor virtual int SendDescriptor(int in_fd); // Get a descriptor - there is no way to sync names or something to them, // so these should be called in pairs - send one, send a ipc command to // the other side to read it, and get it read. If commands are stacked in // order it should be fine. virtual int ReceiveDescriptor(); virtual int SyncIPC(); virtual int SyncRoot() { ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet)); pack->data_len = 0; pack->ipc_cmdnum = rootipcsync_cmd; pack->ipc_ack = 0; return SendIPC(pack); } virtual int ShutdownIPC(ipc_packet *pack); virtual int FetchReadyState(); virtual void RootIPCSynced() { root_ipc_synced = 1; } virtual int FetchRootIPCSynced() { return root_ipc_synced; } protected: virtual void IPCDie(); virtual void ShutdownIPCPassFD(); #ifdef SYS_LINUX // Descriptor to the file descriptor passer (if one exists) int ipc_fd_fd; struct sockaddr_un unixsock; #endif int fdpass_cmd, rootipcsync_cmd; int root_ipc_synced; }; #endif kismet-2013-03-R1b/kis_panel_network.h0000664000175000017500000003641212124602454017350 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_NETWORK_H__ #define __KIS_PANEL_NETWORK_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "netracker.h" #include "kis_clinetframe.h" #include "kis_panel_widgets.h" #include "kis_panel_preferences.h" // Core network display list // // Spun off from the main widgets files due to its size and complexity, I felt // like being organized for once. This also minimally reduces weird dependency // thrash. // // This is the primary logic of the old kismet frontend, moved into a modular // widget. // // This widget (like others) will tunnel all the way to the main interface // class and then configure callbacks for all configured clients to // set up the BSSID protocols. From then on, BSSID updates bypass the // rest of the client system and come directly to the widget for processing. // // This widget attempts to make use of several methods of smartly sorting // the data during mod and insert, and only parsing as much of the incoming // data is necessary to do its job. The primary goal is to minimize or // eliminate the massive CPU loads of hundreds or thousands of networks, // since the bulk of them will not be updating. There is no reason to sort // or recalculate networks which are unchanging. // TODO - add SSID handling and group naming class Kis_Display_NetGroup { public: Kis_Display_NetGroup(); Kis_Display_NetGroup(Netracker::tracked_network *in_net); ~Kis_Display_NetGroup(); // Return a network suitable for display, which could be a single network // or a virtual network aggregated Netracker::tracked_network *FetchNetwork(); // Update the group if there are any dirty networks void Update(); // Add a network to the group void AddNetwork(Netracker::tracked_network *in_net); // Remove a network. Not efficient, so try not to do this too often. void DelNetwork(Netracker::tracked_network *in_net); // Get the number of networks int FetchNumNetworks() { return meta_vec.size(); } // Get the raw network vec vector *FetchNetworkVec() { return &meta_vec; } // Let us know a network has been dirtied void DirtyNetwork(Netracker::tracked_network *in_net); int Dirty() { return dirty; } // Display dirty variables, set after an update int DispDirty() { return dispdirty; } void SetDispDirty(int dd) { dispdirty = dd; } int GetColor() { return color; } void SetColor(int in_c) { color = in_c; } // Cache manipulation, for the header line and sublines. // Details cache is for cached expanded details lines // Grpcache is cached expanded details string GetLineCache() { return linecache; } void SetLineCache(string ic) { linecache = ic; } vector *GetDetCache() { return &detcache; } void SetDetCache(vector& is) { detcache = is; } vector *GetGrpCache() { return &grpcache; } void SetGrpCache(vector& is) { grpcache = is; } // Group name string GetName(); // Hack to get a network name the same way string GetName(Netracker::tracked_network *net); // Set the group name void SetName(string in_name); // Are we expanded in the view? int GetExpanded() { return expanded; } void SetExpanded(int e) { if (e != expanded) ClearSetDirty(); expanded = e; } // Number of lines used in the display, used to recalculate for scrolling void SetNLines(int nl) { nline = nl; } int GetNLines() { return nline; } protected: // Do we need to update? int dirty; // Name string name; // Color int color; // Cached display lines int dispdirty; string linecache; vector detcache; vector grpcache; int nline; // Are we expanded int expanded; // Do we have a local meta network? (ie, do we need to destroy it on our // way our, take special care of it, etc) int local_metanet; // Pointer to the network we return, could be allocated locally, or it could // be a pointer to a network from somewhere else Netracker::tracked_network *metanet; // Vector of networks which compose the metanet. THESE SHOULD NEVER BE FREED, // BECAUSE THEY MAY BE REFERENCED ELSEWHERE. vector meta_vec; // Vector of tracked clients, should never be freed here because they can be // referenced elsewhere vector client_vec; // Clear display data and set dirty void ClearSetDirty(); }; // Smart drawing component which bundles up the networks and displays them // in a fast-sort method which hopefully uses less CPU enum netsort_opts { netsort_autofit, netsort_recent, netsort_type, netsort_channel, netsort_first, netsort_first_desc, netsort_last, netsort_last_desc, netsort_bssid, netsort_ssid, netsort_packets, netsort_packets_desc, netsort_crypt, netsort_sdbm }; /* color array positions */ #define kis_netlist_color_normal 0 #define kis_netlist_color_crypt 1 #define kis_netlist_color_group 2 #define kis_netlist_color_decrypt 3 #define kis_netlist_color_header 4 #define kis_netlist_color_wep 5 #define kis_netlist_color_max 6 // Network columns enum bssid_columns { bcol_decay, bcol_name, bcol_shortname, bcol_nettype, bcol_crypt, bcol_channel, bcol_packdata, bcol_packllc, bcol_packcrypt, bcol_bssid, bcol_packets, bcol_clients, bcol_datasize, bcol_signalbar, bcol_beaconperc, bcol_signal_dbm, bcol_signal_rssi, bcol_freq_mhz, bcol_manuf, bcol_11dcountry, bcol_seenby, bcol_ip, bcol_iprange }; // Do not expect this to be in numerical order with the above enum, this is // for setting up the preferences panels, etc extern const common_col_pref bssid_column_details[]; // Extra display options per-line enum bssid_extras { bext_lastseen, bext_bssid, bext_crypt, bext_ip, bext_manuf, bext_seenby }; extern const common_col_pref bssid_extras_details[]; class Kis_Netlist : public Kis_Panel_Component { public: Kis_Netlist() { // Vector actually being drawn fprintf(stderr, "FATAL OOPS: Kis_Netlist() called w/out globalreg\n"); exit(1); } Kis_Netlist(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Netlist(); virtual void DrawComponent(); virtual void Activate(int subcomponent); virtual void Deactivate(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetPosition(int isx, int isy, int iex, int iey); // Network callback void NetClientConfigure(KisNetClient *in_cli, int in_recon); // Added a client in the panel interface void NetClientAdd(KisNetClient *in_cli, int add); // Filter display (vector of MAC/Mac-masks to filter, display_only == 1 for // only displaying networks which match the filter, 0 for only which do not void SetFilter(vector filter, int display_only); // Kismet protocol parsers void Proto_BSSID(CLIPROTO_CB_PARMS); void Proto_SSID(CLIPROTO_CB_PARMS); void Proto_CLIENT(CLIPROTO_CB_PARMS); void Proto_BSSIDSRC(CLIPROTO_CB_PARMS); void Proto_CLISRC(CLIPROTO_CB_PARMS); void Proto_NETTAG(CLIPROTO_CB_PARMS); void Proto_CLITAG(CLIPROTO_CB_PARMS); // Trigger a sort and redraw update void UpdateTrigger(void); // Fetch a pointer to the currently selected group Kis_Display_NetGroup *FetchSelectedNetgroup(); // Fetch a pointer to the display vector (don't change this! bad things will // happen!) vector *FetchDisplayVector() { return draw_vec; } // Return sort mode netsort_opts FetchSortMode() { return sort_mode; } // Network column text static const char *bssid_columns_text[]; // Parse the bssid columns preferences int UpdateBColPrefs(); // Parse the bssid extras int UpdateBExtPrefs(); // Parse the sort type int UpdateSortPrefs(); protected: int color_map[kis_netlist_color_max]; int color_inactive; time_t bcol_pref_t, bext_pref_t, sort_pref_t; time_t last_mouse_click; // Sort modes // Sort type netsort_opts sort_mode; // Addclient hook reference int addref; // Event reference for update trigger int updateref; // Interface KisPanelInterface *kpinterface; // Drawing offsets into the display vector & other drawing trackers int viewable_lines; int viewable_cols; int first_line, last_line, selected_line; // Horizontal position int hpos; // Assembled protocol fields string asm_ssid_fields, asm_bssid_fields, asm_client_fields, asm_bssidsrc_fields, asm_clisrc_fields; int asm_ssid_num, asm_bssid_num, asm_client_num, asm_bssidsrc_num, asm_clisrc_num; // We try to optimize our memory usage so that there is only // one copy of the TCP data network, as well as only one copy of // the display group network. // // Sorting is optimized to only occur on a full draw update, not during // reception of *BSSID stanzas. Sorting should only occur on the visible // network group (or the visible network group plus or minus a few as // new data is added) // // Raw map of all BSSIDs seen so far from *BSSID sentences macmap bssid_raw_map; // Vector of dirty networks which must be considered for re-sorting vector dirty_raw_vec; // Vector of displayed network groups vector display_vec; // Vector of filtered displayed network groups vector filter_display_vec; // Vector actually being draw vector *draw_vec; // Assembled groups - GID to Group object macmap netgroup_asm_map; // Defined groups, BSSID to GID mapping macmap netgroup_stored_map; // Columns we display vector display_bcols; // Extras we display vector display_bexts; // Filtering vector filter_vec; int display_filter_only, filter_dirty; // Show extended info int show_ext_info; // Cached column headers string colhdr_cache; // Probe, adhoc, and data groups Kis_Display_NetGroup *probe_autogroup, *adhoc_autogroup, *data_autogroup; int DeleteGroup(Kis_Display_NetGroup *in_group); int PrintNetworkLine(Kis_Display_NetGroup *ng, Netracker::tracked_network *net, int rofft, char *rline, int max); }; enum clientsort_opts { clientsort_autofit, clientsort_recent, clientsort_first, clientsort_first_desc, clientsort_last, clientsort_last_desc, clientsort_mac, clientsort_type, clientsort_packets, clientsort_packets_desc, }; // client columns enum client_columns { ccol_decay, ccol_mac, ccol_bssid, ccol_ssid, ccol_packdata, ccol_packllc, ccol_packcrypt, ccol_packets, ccol_datasize, ccol_signal_dbm, ccol_signal_rssi, ccol_freq_mhz, ccol_manuf, ccol_type, ccol_dhcphost, ccol_dhcpvendor, ccol_ip }; /* color array positions */ #define kis_clientlist_color_normal 0 #define kis_clientlist_color_ap 1 #define kis_clientlist_color_wireless 2 #define kis_clientlist_color_adhoc 3 #define kis_clientlist_color_header 4 // Do not expect this to be in numerical order with the above enum, this is // for setting up the preferences panels, etc extern const common_col_pref client_column_details[]; // Extra display options per-line enum client_extras { cext_lastseen, cext_crypt, cext_ip, cext_manuf, cext_dhcphost, cext_dhcpvendor }; extern const common_col_pref client_extras_details[]; class Kis_Clientlist : public Kis_Panel_Component { public: Kis_Clientlist() { fprintf(stderr, "FATAL OOPS: Kis_Clientlist() called w/out globalreg\n"); exit(1); } Kis_Clientlist(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Clientlist(); virtual void DrawComponent(); virtual void Activate(int subcomponent); virtual void Deactivate(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetPosition(int isx, int isy, int iex, int iey); // Trigger a sort and redraw update void UpdateTrigger(void); // We want to pull a new display group from the current network void UpdateDNG(void); // We want to follow the dng every update (default: no, we don't) void FollowDNG(int in_follow) { followdng = in_follow; } // Fetch a pointer to the currently drawing group Kis_Display_NetGroup *FetchSelectedNetgroup(); // Fetch a pointer to the current client Netracker::tracked_client *FetchSelectedClient(); // Return sort mode clientsort_opts FetchSortMode() { return sort_mode; } static const char *client_columns_text[]; struct display_client { Netracker::tracked_client *cli; string cached_line; vector cached_details; int num_lines; int color; }; // Parse the bssid columns preferences int UpdateCColPrefs(); // Parse the bssid extras int UpdateCExtPrefs(); // Parse the sort type int UpdateSortPrefs(); protected: int color_map[5]; int color_inactive; time_t ccol_pref_t, cext_pref_t, sort_pref_t; time_t last_mouse_click; clientsort_opts sort_mode; // Event reference for update trigger int updateref; // Do we follow the DNG and update it continually? int followdng; // Interface KisPanelInterface *kpinterface; // Group we're displaying Kis_Display_NetGroup *dng; // Drawing offsets into the display vector & other drawing trackers int viewable_lines; int viewable_cols; int first_line, last_line, selected_line; // Horizontal position int hpos; // Vector of displayed network clients vector display_vec; // Columns we display vector display_ccols; // Extras we display vector display_cexts; // Show extended info int show_ext_info; // Cached column headers string colhdr_cache; int PrintClientLine(Netracker::tracked_client *cli, int rofft, char *rline, int max); }; enum info_items { info_elapsed, info_numnets, info_numpkts, info_pktrate, info_filtered }; extern const char *info_bits_details[][2]; // Infobits main info pane widget is derived from a packbox - we contain our // own sub-widgets and pack them into ourselves, and let all the other normal // code take care of things like spacing and such. Plugins can then append // after the main info block. class Kis_Info_Bits : public Kis_Panel_Packbox { public: Kis_Info_Bits() { fprintf(stderr, "FATAL OOPS: Kis_Info_Bits()\n"); exit(1); } Kis_Info_Bits(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Info_Bits(); void NetClientConfigure(KisNetClient *in_cli, int in_recon); void NetClientAdd(KisNetClient *in_cli, int add); void Proto_INFO(CLIPROTO_CB_PARMS); void Proto_TIME(CLIPROTO_CB_PARMS); void DrawComponent(); int UpdatePrefs(); protected: int addref; KisPanelInterface *kpinterface; vector infovec; map infowidgets; Kis_Free_Text *title; time_t first_time; time_t last_time; int num_networks; int num_packets; int packet_rate; int filtered_packets; int info_color_normal; string asm_time_fields, asm_info_fields; int asm_time_num, asm_info_num; }; #endif // panel #endif // header kismet-2013-03-R1b/finitestate.cc0000664000175000017500000002564612124602454016316 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "finitestate.h" #include "packetracker.h" #include "util.h" ProbeNoJoinAutomata::ProbeNoJoinAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate) { globalreg = in_globalreg; alertid = globalreg->alertracker->RegisterAlert("PROBENOJOIN", in_unit, in_rate, in_burstrate); } ProbeNoJoinAutomata::~ProbeNoJoinAutomata() { for (map::iterator iter = bssid_map.begin(); iter != bssid_map.end(); ++iter) { delete iter->second; } } int ProbeNoJoinAutomata::ProcessPacket(const packet_info *in_info) { _fsa_element *elem; map::iterator iter; if (in_info->type == packet_management && in_info->subtype == packet_sub_probe_req) { // For probe reqs we look at the source MAC and see what we have. We'll let someone // probe as much as they want, they'd just better answer if a network starts talking to // them. Just make a tracking record that they've been probing if ((iter = bssid_map.find(in_info->source_mac)) == bssid_map.end()) { elem = new _fsa_element; bssid_map[in_info->source_mac] = elem; return 1; } else { return 1; } } else if (in_info->type == packet_management && in_info->subtype == packet_sub_probe_resp) { // Responses create an element if none exists for the destination, and we set anyone getting a // response to state 1 if ((iter = bssid_map.find(in_info->dest_mac)) == bssid_map.end()) { elem = new _fsa_element; bssid_map[in_info->dest_mac] = elem; } else { elem = iter->second; } if (elem->state <= 1) { elem->state = 1; elem->counter++; // Trigger on threshold if (elem->counter > 25) { char atext[STATUS_MAX]; snprintf(atext, STATUS_MAX, "Suspicious client %s - probing networks but never participating.", iter->first.Mac2String().c_str()); globalreg->alertracker->RaiseAlert(alertid, 0, iter->first, 0, 0, in_info->channel, atext); } } return 1; } else if (in_info->type == packet_data) { // If they look like a netstumbler packet, we don't let them go if (in_info->proto.type == proto_netstumbler || in_info->proto.type == proto_lucenttest || in_info->proto.type == proto_wellenreiter) return 1; // If the source is our person, they're exonerated - they're doing normal traffic if ((iter = bssid_map.find(in_info->source_mac)) == bssid_map.end()) { elem = new _fsa_element; bssid_map[in_info->source_mac] = elem; } else { elem = iter->second; } elem->state = 2; return 1; } return 0; } DisassocTrafficAutomata::DisassocTrafficAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate) { globalreg = in_globalreg; alertid = globalreg->alertracker->RegisterAlert("DISASSOCTRAFFIC", in_unit, in_rate, in_burstrate); } DisassocTrafficAutomata::~DisassocTrafficAutomata() { } int DisassocTrafficAutomata::ProcessPacket(const packet_info *in_info) { _fsa_element *elem; map::iterator iter; char atext[STATUS_MAX]; if (in_info->type == packet_management && in_info->subtype == packet_sub_disassociation) { iter = source_map.find(in_info->source_mac); if (iter == source_map.end()) { elem = new _fsa_element; source_map[in_info->source_mac] = elem; elem->counter = 0; } else { elem = iter->second; } elem->state = 0; gettimeofday(&elem->last_time, NULL); } else if (in_info->type == packet_management && in_info->subtype == packet_sub_deauthentication) { iter = source_map.find(in_info->source_mac); if (iter == source_map.end()) { elem = new _fsa_element; source_map[in_info->source_mac] = elem; elem->counter = 0; } else { elem = iter->second; } elem->state = 1; gettimeofday(&elem->last_time, NULL); } else if (in_info->type == packet_data) { iter = source_map.find(in_info->source_mac); if (iter == source_map.end()) return 0; elem = iter->second; struct timeval tv; gettimeofday(&tv, NULL); // Raise an alert if someone is exchanging data w/in 10 seconds of disassociating or deauthenticating if (tv.tv_sec - elem->last_time.tv_sec < 10) { elem->counter++; snprintf(atext, STATUS_MAX, "Suspicious traffic on %s. Data traffic within 10 seconds of disassociate.", in_info->source_mac.Mac2String().c_str()); globalreg->alertracker->RaiseAlert(alertid, in_info->bssid_mac, in_info->source_mac, 0, 0, in_info->channel, atext); return 1; } else { delete[] iter->second; source_map.erase(iter); } } return 0; } BssTimestampAutomata::BssTimestampAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate) { globalreg = in_globalreg; alertid = globalreg->alertracker->RegisterAlert("BSSTIMESTAMP", in_unit, in_rate, in_burstrate); } BssTimestampAutomata::~BssTimestampAutomata() { for (macmap::iterator iter = bss_map.begin(); iter != bss_map.end(); ++iter) { delete iter->second; } } int BssTimestampAutomata::ProcessPacket(const packet_info *in_info) { _bs_fsa_element *elem; char atext[1024]; // Don't track BSS timestamp for non-beacon frames or for adhoc networks if (in_info->timestamp == 0 || in_info->type != packet_management || in_info->subtype != packet_sub_beacon || in_info->distrib == adhoc_distribution) return 0; macmap::iterator iter = bss_map.find(in_info->bssid_mac); if (iter == bss_map.end()) { elem = new _bs_fsa_element; elem->bss_timestamp = in_info->timestamp; bss_map.insert(in_info->bssid_mac, elem); return 0; } else { elem = *(iter->second); } if (in_info->timestamp < elem->bss_timestamp) { if (elem->counter > 0) { // Generate an alert, we're getting a bunch of invalid timestamps snprintf(atext, STATUS_MAX, "Out-of-sequence BSS timestamp on %s " "- got %llx, expected %llx - this could indicate AP spoofing", in_info->bssid_mac.Mac2String().c_str(), in_info->timestamp, elem->bss_timestamp); globalreg->alertracker->RaiseAlert(alertid, in_info->bssid_mac, 0, 0, 0, in_info->channel, atext); // Reset so we don't keep thrashing here elem->counter = 0; elem->bss_timestamp = in_info->timestamp; return 1; } else { // Increase our invalid stock elem->counter += 10; } } else if (elem->counter > 0) { elem->counter--; } elem->bss_timestamp = in_info->timestamp; return 0; } WepRebroadcastAutomata::WepRebroadcastAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate) { globalreg = in_globalreg; alertid = globalreg->alertracker->RegisterAlert("WEPREBROADCAST", in_unit, in_rate, in_burstrate); } WepRebroadcastAutomata::~WepRebroadcastAutomata() { } int WepRebroadcastAutomata::ProcessPacket(const packet_info *in_info) { return 0; } #if 0 SequenceSpoofAutomata::SequenceSpoofAutomata(Packetracker *in_ptracker, Alertracker *in_atracker, alert_time_unit in_unit, int in_rate, int in_burstrate) { atracker = in_atracker; ptracker = in_ptracker; alertid = atracker->RegisterAlert("SEQUENCESPOOF", in_unit, in_rate, in_burstrate); } SequenceSpoofAutomata::~SequenceSpoofAutomata() { } int SequenceSpoofAutomata::ProcessPacket(const packet_info *in_info) { // Only sequence-track beacons (for now) int ret = 0; char atext[STATUS_MAX]; if (in_info->type != packet_management || in_info->subtype != packet_sub_beacon) return 0; // See if we know about this network wireless_network *net = ptracker->MatchNetwork(in_info); if (net != NULL) { // If we found a network for this packet, see if it's got a sequence mismatch. // remember we modulo the sequence by 4096, so we won't worry about a sequence drop // if the network used to be near the wraparound if (net->last_sequence < 4000 && net->last_sequence != 0 && (in_info->sequence_number < net->last_sequence)) { snprintf(atext, STATUS_MAX, "Suspicious sequence change - %s %d to %d. Possible spoof attempt.", net->bssid.Mac2String().c_str(), net->last_sequence, in_info->sequence_number); atracker->RaiseAlert(alertid, atext); } } /* // Try to match the mac addr to an existing network map::iterator iter; // If we have more than 2 suspicious MAC changes in the records, raise an alert. if (count > 2) { char atext[STATUS_MAX]; snprintf(atext, STATUS_MAX, "Suspicious sequence order - %s looks like %s (%d to %d). Possible FakeAP.", in_info->source_mac.Mac2String().c_str(), seq->source_mac.Mac2String().c_str(), in_info->sequence_number, seq->seq_num); atracker->RaiseAlert(alertid, atext); fprintf(stderr, "**FORCED** %s\n", atext); ret = 1; } // Put it on the stack seq = new _seq_elem; seq->seq_num = in_info->sequence_number; seq->source_mac = in_info->source_mac; seq_stack.push_back(seq); if (seq_stack.size() > 150) { delete seq_stack[0]; seq_stack.erase(seq_stack.begin()); } */ return ret; } #endif kismet-2013-03-R1b/netframework.h0000664000175000017500000001417312124602454016336 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __NETFRAMEWORK_H__ #define __NETFRAMEWORK_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "messagebus.h" #include "timetracker.h" #include "globalregistry.h" #include "ringbuf.h" #include "pollable.h" // Basic superclass frameworks for network servers // Forward prototypes // NetworkServer should be subclassed into the basic TCP, SSL, UDP, etc // backend mechanisms that establish a server class NetworkServer; // ServerInterface should be subclassed into the protocol handlers that // actually map writing to and from a client, parsing their data, etc class ServerFramework; // Skeleton for a network server class NetworkServer : public Pollable { public: NetworkServer(); NetworkServer(GlobalRegistry *in_globalreg); virtual ~NetworkServer() { } // Register global infra virtual void RegisterGlobals(GlobalRegistry *in_reg) { globalreg = in_reg; } // Register a server framework (mirrored by the SF's registerserver virtual void RegisterServerFramework(ServerFramework *in_frm) { srvframework = in_frm; } // Is the server valid for any other ops? virtual int Valid() { return sv_valid; } // Generic stuff that every network-y server will need to do. // Most of this needs to be overridden // Core select loop merge - combine FDs with the master FD list, and // handle a strobe across pending FDs virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); // Flush all output buffers if we can virtual int FlushRings(); // Kill a connection by client ID - We define a stub that children // can use to do the lowlevel cleanup virtual void KillConnection(int in_fd); // Number of clients (cheat by grabbing the size of the write map) virtual int FetchNumClients() { return (int) write_buf_map.size(); } // Fetch a set of pending client descriptors, ie, clients with // something in their read buffers virtual void FetchPendingClients(fd_set *ret_pending) { ret_pending = &pending_readset; } // Read, write, and mark are essentially fallthroughs directly to // the ringbuffers. We actually define these since it's // unlikely that they'd be drastically overridden // Write data to a client virtual int WriteData(int in_clid, void *in_data, int in_len); // Amount of data pending in a client ring virtual int FetchReadLen(int in_clid); // Read data from a client virtual int ReadData(int in_clid, void *ret_data, int in_max, int *ret_len); // Mark data on a client as read (ie, we've extracted it and parsed it) virtual int MarkRead(int in_clid, int in_readlen); // Fetch a vector of all the current clients for mass-writes virtual int FetchClientVector(vector *ret_vec); // Fetch info about a client, cast it into whatever makes sense for the // future virtual int FetchClientConnectInfo(int in_clid, void *ret_info) = 0; // Fetch a clients remote address virtual string GetRemoteAddr(int in_fd) = 0; // Enable server virtual int EnableServer() = 0; // Shutdown the server virtual void Shutdown() = 0; protected: // Broker various acceptance stuff virtual int Accept() = 0; // Validate a connection virtual int Validate(int in_fd) = 0; // Read pending bytes from whereever into the ringbuffer virtual int ReadBytes(int in_fd) = 0; // Write pending bytes from the ringbuffer to whatever virtual int WriteBytes(int in_fd) = 0; char errstr[STATUS_MAX]; int sv_valid; int serv_fd; GlobalRegistry *globalreg; ServerFramework *srvframework; fd_set server_fdset; fd_set pending_readset; // Read ring buffers map read_buf_map; // Write ring buffers map write_buf_map; int max_fd; }; // Skeleton to a protocol interface class ServerFramework { public: ServerFramework() { globalreg = NULL; netserver = NULL; }; ServerFramework(GlobalRegistry *in_reg) { globalreg = in_reg; netserver = NULL; } virtual ~ServerFramework() { }; // Register infra globals virtual void RegisterGlobals(GlobalRegistry *in_reg) { globalreg = in_reg; } // Register the network server core that we use to talk out void RegisterNetworkServer(NetworkServer *in_nets) { netserver = in_nets; } // Is this setup valid? virtual int Valid() { return valid; } // Handle new connections virtual int Accept(int in_fd) = 0; // Parse data on a given file descriptor virtual int ParseData(int in_fd) = 0; // Kill a connection virtual int KillConnection(int in_fd) = 0; // Shutdown the protocol virtual int Shutdown(); // The ring buffer was drained... If we have anything cached in the // framework to try to send to the client, this is how we should do it. virtual int BufferDrained(int in_fd); protected: char errstr[STATUS_MAX]; int valid; GlobalRegistry *globalreg; NetworkServer *netserver; }; #endif kismet-2013-03-R1b/apple80211.h0000664000175000017500000003117312124602454015326 0ustar dragorndragorn/* From MacStumbler, which is under GPL */ /* * Apple80211.h * * This is the reverse engineered header for the Apple80211 private framework. * The framework can be found at /System/Library/PrivateFrameworks/Apple80211.framework. * Linking with Apple80211.framework requires CoreFoundation.framework and AppKit.framework. * * Note that there is also information in the IORegistry, see * ioreg -c AirPortDriver -w 0 * * Contributors: * korben - korben@cox.net * jason - catalyst@mac.com * ragge - ragge@nada.kth.se * * Last updated by korben on 5/15/2002 */ /* ChangeLog: 2002-05-14 ragge Changed argument types and count to procedures Added WirelessScan Changed name of unknown field to beaconInterval Added error values and error return types 2002-05-15 korben Combined ragge's changes with jason's 2002-05-17 korben fixed adhoc and mangaged WINetworkInfoFlags per ragge's request Added WirelessEncrypt and WirelessKey declarations Updated WirelessJoinWEP and WirelessMakeIBSS comments regarding keys */ #ifndef __APPLE_80211__ #define __APPLE_80211__ #include /* A WirelessContext should be created using WirelessAttach before any other Wireless functions are called. WirelessDetach is used to dispose of a WirelessContext. */ typedef struct __WirelessContext *WirelessContextPtr; struct WirelessInfo { UInt16 link_qual; /* Link quality, percent? */ UInt16 comms_qual; /* Communication Quality */ UInt16 signal; /* Signal level */ UInt16 noise; /* Noise level */ UInt16 port_stat; /* HERMES_RID_PORTSTAT? (Uncertain about the meaning of this! 1=off? 2=connetion bad? 3=AdHoc Create? 4=BSS (Client)? 5=BSS+OutOfRange?) */ UInt16 client_mode; /* 1 = BSS, 4 = Create IBSS */ UInt16 u7; /* ? */ UInt16 power; /* Power on flag */ UInt16 u9; /* 0=bad?, 1=ok?, 2=wrong key? */ UInt8 macAddress[6]; /* MAC address of wireless access point. */ SInt8 name[34]; /* Name of current (or wanted?) network. */ }; typedef struct WirelessInfo WirelessInfo; /* I'm not sure what most of the values in the WirelessInfo structure are for, but here are some examples of the numbers returned: With Airport Off: 0 0 0 0 1 1 0 0 1 With Airport On: 72 22 31 9 4 1 0 1 1 With Computer to Computer Network: 0 0 0 0 3 4 0 1 1 - jason */ /* WINetworkInfoFlags are used in the WirelessNetworkInfo struct returned by the WirelessScanSplit function. I have seen other flags, but I don't know what they stand for. - korben I think these should probably be bit masks, but I am using what korben figured out. - jason */ typedef UInt16 WINetworkInfoFlags; enum { kWINetworkManagedFlag = 0x0001, kWINetworkAdhocFlag = 0x0002, kWINetworkEncryptedFlag = 0x0010 }; typedef SInt32 WIErr; enum { airpParamErr = -2013261823, /* 0x88001001 */ airpNoIOServiceErr = -2013261822, /* 0x88001002 */ airpInternalErr = -2013261821, /* 0x88001003 */ airpUnk4Err = -2013261820, /* 0x88001004 */ airpOutOfMemErr = -2013261819, /* 0x88001005 */ airpInternal2Err = -2013261818, /* 0x88001006 */ airpUnk7Err = -2013261817, /* 0x88001007 */ airpUnk8Err = -2013261816, /* 0x88001008 */ airpUnk9Err = -2013261815, /* 0x88001009 */ airpUnkaErr = -2013261814, /* 0x8800100a */ airpNoPowerErr = -2013261813 /* 0x8800100b */ }; /* The meaning of these error codes can be wrong, and the list is not * complete. In general checking for noErr (0) should be enough */ struct WirelessNetworkInfo { UInt16 channel; /* Channel for the network. */ UInt16 noise; /* Noise for the network. 0 for Adhoc. */ UInt16 signal; /* Signal strength of the network. 0 for Adhoc. */ UInt8 macAddress[6]; /* MAC address of the wireless access point. */ UInt16 beaconInterval; /* beacon interval in milliseconds */ WINetworkInfoFlags flags; /* Flags for the network. */ UInt16 nameLen; SInt8 name[32]; }; typedef struct WirelessNetworkInfo WirelessNetworkInfo; typedef UInt8 WirelessKey[13]; // For use with WirelessEncrypt /* * WirelessIsAvailable() * * Returns 1 if a wireless interface is available, 0 otherwise */ extern int WirelessIsAvailable(void); /* * WirelessAttach() * * WirelessAttach should be called before all other Wireless functions. * * outContext returns the contextPtr you will pass * to all other Wireless functions * The second argument must be zero. */ extern WIErr WirelessAttach( WirelessContextPtr *outContext, const UInt32); /* * WirelessDetach() * * WirelessDetach is called after you are done calling Wireless functions. * It will free all memory being used by the library. * * inContext is the contextPtr you want to dispose of. */ extern WIErr WirelessDetach( WirelessContextPtr inContext); /* * WirelessGetPower() * * WirelessGetPower returns the power state of Airport. * * inContext is the contextPtr created by WirelessAttach. * outPower is 0 for off and 1 for on. */ extern WIErr WirelessGetPower( WirelessContextPtr inContext, UInt8 *outPower); /* * WirelessSetPower() * * WirelessSetPower will turn Airport on or off. * * inContext is the contextPtr created by WirelessAttach. * inPower is 0 for off and 1 for on. */ extern WIErr WirelessSetPower( WirelessContextPtr inContext, UInt8 inPower); /* * WirelessGetEnabled() * * WirelessGetEnabled could have returned the Enabled state of Airport, * but it seems to rather return the Power state. * * inContext is the contextPtr created by WirelessAttach. * outEnabled is 0 for off and 1 for on. */ extern WIErr WirelessGetEnabled( WirelessContextPtr inContext, UInt8 *outEnabled); /* * WirelessSetEnabled() * * WirelessSetEnabled will enable or disable Airport communication. * * inContext is the contextPtr created by WirelessAttach. * inEnabled is 0 for off and 1 for on. */ extern WIErr WirelessSetEnabled( WirelessContextPtr inContext, UInt32 inEnabled); /* * WirelessGetInfo() * * WirelessGetInfo returns info about the state * of the current wireless connection. * * inContext is the contextPtr created by WirelessAttach. * outInfo is a WirelessInfo structure containing state info. */ extern WIErr WirelessGetInfo( WirelessContextPtr inContext, WirelessInfo *outInfo); /* * WirelessScanSplit(), WirelessScan() * * WirelessScanSplit scans for available wireless networks. * It will allocate 2 CFArrays to store a list * of managed and adhoc networks. The arrays hold CFData * objects which contain WirelessNetworkInfo structures. * Note: An adhoc network created on the computer the * scan is running on will not be found. WirelessGetInfo * can be used to find info about a local adhoc network. * * inContext is the contextPtr created by WirelessAttach. * apList will contain a CFArrayRef of managed networks. * adhocList will contain a CFArrayRef of adhoc networks. * For example: * WirelessScanSplit(clientContext, &apList, &adhocList, 1) * * If stripDups != 0 only one basestation for each SSID will be returned * * WirelessScan works the same way but does not split the list by AP type */ extern WIErr WirelessScanSplit( WirelessContextPtr inContext, CFArrayRef *apList, CFArrayRef *adhocList, const UInt32 stripDups); extern WIErr WirelessScan( WirelessContextPtr inContext, CFArrayRef *apList, const UInt32 stripDups); /* * WirelessJoin() * * WirelessJoin is used to join a Wireless network. * * inContext is the contextPtr created by WirelessAttach. * inNetworkName is the name of the network to join. */ extern WIErr WirelessJoin( WirelessContextPtr inContext, CFStringRef inNetworkName); /* * WirelessJoinWEP() * * WirelessJoinWEP is used to join an encrypted network. * * inContext is the contextPtr created by WirelessAttach. * inNetworkName is the name of the network to join. * inNetworkPassword is the password/key of the network. * * inNetworkPassword description: * - Passwords are just a string of any length, they will be hashed into a key. * - Keys should be passed as a hex string, optionally beginning with 0x, * and must be either 10 digits for a 40bit key or 26 digits for a 104bit key, * or an ascii/binary representation of the key, 5 or 13 bytes long. * - It can also be the empty string, meaning no encryption. * * For more info see: * http://kbase.info.apple.com/cgi-bin/WebObjects/kbase.woa/11/wa/query?searchMode=Expert&type=id&val=KC.106424 */ extern WIErr WirelessJoinWEP( WirelessContextPtr inContext, CFStringRef inNetworkName, CFStringRef inNetworkPassword); /* * WirelessEncrypt * * WirelessEncrypt is called from WirelessJoinWEP and * WirelessMakeIBSS to translate a string into a 40 or * 104-bit Apple hashed WEP key. * Third argument is 0 for 40 bit key and 1 for 104 bit key. * * Sample usage: * * WirelessKey myKey; * WirelessEncrypt(@"password", &myKey, 1); * for(int i=0; i <= 12; i++) * printf("%.2X ", myKey[i]); * */ extern WIErr WirelessEncrypt( CFStringRef inNetworkPassword, WirelessKey *wepKey, const UInt32 use104bits); /* * WirelessGetChannels() * * WirelessGetChannels is used to get valid channels for * creating an adhoc network. * * inContext is the contextPtr created by WirelessAttach. * outChannelBitField contains a bit field of valid channels. * For example if 0x07FF is returned then bits 0 through 10 * are set, which means channels 1 through 11 are valid. */ extern WIErr WirelessGetChannels( WirelessContextPtr inContext, UInt16 *outChannelBitField); /* * WirelessGetBestChannel() * * WirelessGetBestChannel is used to get the best channel * for creating an adhoc network on. * * inContext is the contextPtr created by WirelessAttach. * outBestChannel is the best channel for a wireless network. */ extern WIErr WirelessGetBestChannel( WirelessContextPtr inContext, UInt16 *outBestChannel); /* * WirelessMakeIBSS() * * WirelessMakeIBSS is used to create a computer to computer * adhoc wireless network. * * inContext is the contextPtr created by WirelessAttach. * inNetworkName is the name of the network to create. * inNetworkPassword is the password/key for the new network. * inChannel is the wireless channel the network will use. * * inNetworkPassword description: * - Passwords are just a string of any length, they will be hashed into a key. * - Keys should be passed as a hex string, optionally beginning with 0x, * and must be either 10 digits for a 40bit key or 26 digits for a 104bit key. * - It can also be the empty string, meaning no encryption. * * For more info see: * http://kbase.info.apple.com/cgi-bin/WebObjects/kbase.woa/11/wa/query?searchMode=Expert&type=id&val=KC.106424 */ extern WIErr WirelessMakeIBSS( WirelessContextPtr inContex, CFStringRef inNetworkName, CFStringRef inNetworkPassword, UInt32 inChannel); /* * Get information from the Hermes chip. * * RIDno is the Hermes RID number for the data to get, as * 0xFC01 - HERMES_RID_CNFOWNMACADDR * 0xFC02 - HERMES_RID_CNFDESIREDSSID * 0xFDC1 - HERMES_RID_CURRENTCHANNEL * and so on. * Don't know why, but 0xF100 - HERMES_INQ_TALLIES works here too, * and a struct with the counters will be returned. (The data * returned seems to be lagging, though, call twice for fresh data.) */ extern WIErr WirelessHCF_GetInfo( WirelessContextPtr inContext, UInt16 RIDno, UInt32 outBufSize, void *outBuf); /* ***** MISSING FUNCTIONS ***** These functions are used to configure an Access Point (Base Station). Most of these are used by the Airport Admin Utility.app, and some like WirelessAP_GetStatus are even used by Internet Connect.app. - jason WirelessAP_BinaryCurrentVersion WirelessAP_BinaryCurrentVersion2 WirelessAP_BinaryIsCurrent WirelessAP_BinaryUpload WirelessAP_BinaryUploadACP WirelessAP_BinaryVersion WirelessAP_Dial WirelessAP_DialDynamic WirelessAP_Explore WirelessAP_ForceIPAddress WirelessAP_GetBridgeStatus WirelessAP_GetCommonVariables WirelessAP_GetCommonVariablesACP WirelessAP_GetFullStatus WirelessAP_GetModemVersion WirelessAP_GetModemVersionACP WirelessAP_GetStatus WirelessAP_GetType WirelessAP_GetVersion WirelessAP_Hangup WirelessAP_IsConnected WirelessAP_Read WirelessAP_ReadACP WirelessAP_ResetNVRAM WirelessAP_Restart WirelessAP_RestartACP WirelessAP_Write WirelessAP_WriteACP I can't find any apps that use these functions. - jason WirelessAccessPoint WirelessConfigure WirelessDownloadFW WirelessSetKey */ extern WIErr WirelessPrivate(WirelessContextPtr inContext,void* in_ptr,int in_bytes,void* out_ptr,int out_bytes); #endif // __APPLE_80211__ kismet-2013-03-R1b/finitestate.h0000664000175000017500000001266112124602454016151 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __FINITESTATE_H__ #define __FINITESTATE_H__ #include "config.h" #include #include #include "globalregistry.h" #include "alertracker.h" // Finite state automata superclass which handles a category of tracking conditions. // It's possible that there can be multiple state machines of a single category // (ie, tracking multiple potential quesitionable MACs); the FiniteAutomata is // responsible for handling these in whatever sane manner is necessary and for // timing out old conections. class FiniteAutomata { public: // An individual state element class _fsa_element { public: _fsa_element() { last_time.tv_sec = start_time.tv_sec = death_time.tv_sec = 0; last_time.tv_usec = start_time.tv_usec = death_time.tv_usec = 0; state = 0; counter = 0; } struct timeval last_time; struct timeval start_time; struct timeval death_time; int state; int counter; }; virtual ~FiniteAutomata() { } // Handle a packet virtual int ProcessPacket(const packet_info *in_info) = 0; int FetchAlertRef() { return alertid; } protected: GlobalRegistry *globalreg; int alertid; }; // Finite state automata to watch people who probe and never exchange data after an association class ProbeNoJoinAutomata : public FiniteAutomata { public: ProbeNoJoinAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate); ~ProbeNoJoinAutomata(); // States: // State 0: Probe only // State 1: Probe and response seen // State 2: Normal user, probe response and data seen // Threshold if state == 2 && counter is over threshold int ProcessPacket(const packet_info *in_info); protected: // Map of probing clients to responding people. If the client sends any "normal" data // destined to that network, we reset them. map bssid_map; }; // FSA to look for a disassociate/deauth from a client who then keeps talking. This is // suspicious behavior. Based on "802.11 Denial-of-Service Attacks: Real Vulnerabilities // and Practical Solutions", Bellardo, J. and Savage, S. class DisassocTrafficAutomata : public FiniteAutomata { public: DisassocTrafficAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate); ~DisassocTrafficAutomata(); int ProcessPacket(const packet_info *in_info); protected: // State 0 - got a disassoc // State 1 - got a deauth map source_map; }; // FSA to look for spoofing via BSS timestamp. // BSS timestamps are monotonically increasing within the BSSID for all times they're defined // An invalid timestamp increases us by 10, a valid timestamp decreases by one. This is a // cheap way to keep track of how much we're flapping - we don't want a reboot of an AP to // generate an alert, but we DO want a spoofed AP beaconing in the same space to generate // one. class BssTimestampAutomata : public FiniteAutomata { public: class _bs_fsa_element : public FiniteAutomata::_fsa_element { public: _bs_fsa_element() { bss_timestamp = 0; } uint64_t bss_timestamp; }; BssTimestampAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate); ~BssTimestampAutomata(); int ProcessPacket(const packet_info *in_info); protected: macmap bss_map; }; // Detect broadcast replay WEP attacks by looking for bursts of packets with the same // IV and ICV class WepRebroadcastAutomata : public FiniteAutomata { public: WepRebroadcastAutomata(GlobalRegistry *in_globalreg, alert_time_unit in_unit, int in_rate, int in_burstrate); ~WepRebroadcastAutomata(); int ProcessPacket(const packet_info *in_info); protected: class _wreb_element : public _fsa_element { // Just add a wep field tracker uint32_t wepfield; }; map source_map; }; #if 0 // This doesn't really work so we won't use it. // Finite state automata to watch sequence numbers class SequenceSpoofAutomata : public FiniteAutomata { public: SequenceSpoofAutomata(Packetracker *in_ptracker, Alertracker *in_atracker, alert_time_unit in_unit, int in_rate, int in_burstrate); ~SequenceSpoofAutomata(); int ProcessPacket(const packet_info *in_info); protected: // State 0 - Undefined source // State 1 - Source with beacons only // State 2 - Source with real traffic map seq_map; }; #endif #endif kismet-2013-03-R1b/alertracker.h0000664000175000017500000001122212124602454016121 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ALERTRACKER_H__ #define __ALERTRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include "globalregistry.h" #include "messagebus.h" #include "packetchain.h" #include "timetracker.h" #include "kis_netframe.h" class kis_alert_info : public packet_component { public: kis_alert_info() { tm.tv_sec = 0; tm.tv_usec = 0; channel = 0; // We do NOT self-destruct because we get cached in the alertracker // for playbacks. It's responsible for discarding us self_destruct = 0; } string header; struct timeval tm; mac_addr bssid; mac_addr source; mac_addr dest; mac_addr other; int channel; string text; }; class kis_alert_component : public packet_component { public: kis_alert_component() { // We can self destruct because we won't clear out the vector // of actual alert info self_destruct = 1; } vector alert_vec; }; enum ALERT_fields { ALERT_sec, ALERT_usec, ALERT_header, ALERT_bssid, ALERT_source, ALERT_dest, ALERT_other, ALERT_channel, ALERT_text, ALERT_maxfield }; int Protocol_ALERT(PROTO_PARMS); // kis_alert_info void Protocol_ALERT_enable(PROTO_ENABLE_PARMS); static const int alert_time_unit_conv[] = { 1, 60, 3600, 86400 }; enum alert_time_unit { sat_second, sat_minute, sat_hour, sat_day }; class Alertracker { public: // A registered alert type struct alert_rec { int ref_index; string header; // Units limiting is measured in alert_time_unit limit_unit; // Alerts per unit int limit_rate; // Units burst is measured in alert_time_unit burst_unit; // Alerts sent before limiting takes hold int limit_burst; // How many alerts have been sent burst-mode (decremented once per unit) int burst_sent; // How many have we sent in total? int total_sent; // Last time we sent an alert, to tell if we can reset the burst or // rate counters time_t time_last; }; // Simple struct from reading config lines struct alert_conf_rec { string header; alert_time_unit limit_unit; int limit_rate; alert_time_unit burst_unit; int limit_burst; }; Alertracker(); Alertracker(GlobalRegistry *in_globalreg); ~Alertracker(); // Register an alert and get an alert reference number back. int RegisterAlert(const char *in_header, alert_time_unit in_unit, int in_rate, alert_time_unit in_burstunit, int in_burst); // Find a reference from a name int FetchAlertRef(string in_header); // Will an alert succeed? int PotentialAlert(int in_ref); // Raise an alert ... int RaiseAlert(int in_ref, kis_packet *in_pack, mac_addr bssid, mac_addr source, mac_addr dest, mac_addr other, int in_channel, string in_text); // Send backlogged alerts void BlitBacklogged(int in_fd); // Load an alert reference from a config file (not tied only to the // kismet conf in globalreg) int ParseAlertStr(string alert_str, string *ret_name, alert_time_unit *ret_limit_unit, int *ret_limit_rate, alert_time_unit *ret_limit_burst, int *ret_burst_rate); // Load alert rates from a config file... Called on kismet_config by // default int ParseAlertConfig(ConfigFile *in_conf); // Activate a preconfigured alert from a file int ActivateConfiguredAlert(const char *in_header); const vector *FetchBacklog(); protected: // Check and age times int CheckTimes(alert_rec *arec); // Parse a foo/bar rate/unit option int ParseRateUnit(string in_ru, alert_time_unit *ret_unit, int *ret_rate); GlobalRegistry *globalreg; int next_alert_id; map alert_name_map; map alert_ref_map; vector alert_backlog; int num_backlog; map alert_conf_map; }; #endif kismet-2013-03-R1b/packetsource_bsdrt.h0000664000175000017500000000712612124602454017520 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * BSD is the generic BSD layer for capturing packets and controlling interfaces * */ #ifndef __PACKETSOURCE_BSD_H__ #define __PACKETSOURCE_BSD_H__ #include "config.h" #if (defined(HAVE_LIBPCAP) && (defined(SYS_OPENBSD) || defined(SYS_NETBSD) || \ defined(SYS_FREEBSD))) #include #include #include "globalregistry.h" #include "messagebus.h" #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #define USE_PACKETSOURCE_BSDRT #define KDLT_BSD802_11 -100 #define KDLT_IEEE802_11_RADIO 127 // BSD packet source controller class, handles all the mode, channel, etc setting. // Thanks to Sam Leffler and Pedro la Peu for the original variant and OpenBSD // updates of this class Radiotap_BSD_Controller { public: Radiotap_BSD_Controller(GlobalRegistry *in_globalreg, string in_dev); ~Radiotap_BSD_Controller(); int MonitorEnable(); int MonitorReset(); int ChangeChannel(int in_ch); int GetMediaOpt(int& options, int& mode); int SetMediaOpt(int options, int mode); int GetIfFlags(int &flags); int SetIfFlags(int value); int Get80211(int type, int& val, int len, uint8_t *data); int Set80211(int type, int val, int len, uint8_t *data); protected: GlobalRegistry *globalreg; int CheckSocket(); int sock; int prev_flags; int prev_options; int prev_mode; int prev_chan; string dev; }; // BSD radiotap class PacketSource_BSDRT : public PacketSource_Pcap { public: // HANDLED PACKET SOURCES: // radiotap_bsd_ag // radiotap_bsd_a // radiotap_bsd_g // radiotap_bsd_b PacketSource_BSDRT() { fprintf(stderr, "FATAL OOPS: Packetsource_BSDRT() called\n"); exit(1); } PacketSource_BSDRT(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { bsdcon = NULL; } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_BSDRT(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_BSDRT(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { bsdcon = new Radiotap_BSD_Controller(in_globalreg, in_interface.c_str()); } virtual ~PacketSource_BSDRT() { } virtual int FetchChannelCapable() { return 1; } virtual int EnableMonitor(); virtual int DisableMonitor(); virtual int SetChannel(unsigned int in_ch); virtual int FetchHardwareChannel(); protected: Radiotap_BSD_Controller *bsdcon; // Override data link type to handle bsd funky bits virtual int DatalinkType(); // BSD radio fetch virtual void FetchRadioData(kis_packet *in_packet); // Check that we support the dlt we need virtual int CheckDLT(int dlt); }; #endif /* have_libpcap && BSD */ #endif kismet-2013-03-R1b/config.sub0000775000175000017500000010532712124602454015446 0ustar dragorndragorn#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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 2 of the License, or # (at your option) any later version. # # This program 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: kismet-2013-03-R1b/dumpfile_alert.h0000664000175000017500000000255512124602454016627 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_ALERT_H__ #define __DUMPFILE_ALERT_H__ #include "config.h" #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "alertracker.h" #include "dumpfile.h" // Hook for grabbing packets int dumpfilealert_chain_hook(CHAINCALL_PARMS); // Pcap-based packet writer class Dumpfile_Alert : public Dumpfile { public: Dumpfile_Alert(); Dumpfile_Alert(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Alert(); virtual int chain_handler(kis_packet *in_pack); virtual int Flush(); protected: FILE *alertfile; }; #endif /* __dump... */ kismet-2013-03-R1b/unixdomainserver.cc0000664000175000017500000001636112124602454017373 0ustar dragorndragorn#include "unixdomainserver.h" #include "configfile.h" #include UnixDomainServer::UnixDomainServer() { fprintf(stderr, "*** FATAL OOPS: UnixDomainServer()\n"); exit(1); } UnixDomainServer::UnixDomainServer(GlobalRegistry *in_globalreg) : NetworkServer(in_globalreg) { globalreg = in_globalreg; // Init stuff sv_valid = 0; sv_configured = 0; serv_fd = 0; max_fd = 0; int_ring_len = UNIX_SRV_RING_LEN; FD_ZERO(&server_fdset); } UnixDomainServer::~UnixDomainServer() { if(serv_fd) ::unlink(socket_path.c_str()); } // Set up the Unix-domain socket and listening int UnixDomainServer::SetupServer(const std::string& path, int mode, bool force, unsigned int in_maxcli) { socket_path = path; maxcli = in_maxcli; sv_configured = 1; socket_mode = mode; if(force) ::unlink(path.c_str()); globalreg->RegisterPollableSubsys(this); return 1; } // Set the length of the rings for new connections void UnixDomainServer::SetRingSize(int in_sz) { int_ring_len = in_sz; } int UnixDomainServer::EnableServer() { if (sv_configured == 0) { _MSG("Attempted to enable unconfigured Unix domain server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Set up socket stuff memset(&serv_sock, 0, sizeof(serv_sock)); serv_sock.sun_family = AF_UNIX; strncpy(serv_sock.sun_path, socket_path.c_str(), UNIX_PATH_MAX); if ((serv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { _MSG("Unix domain server socket() failed: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } // Bind the socket if (bind(serv_fd, (struct sockaddr *) &serv_sock, sizeof(serv_sock)) < 0) { _MSG("Unix domain server bind() failed: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } // Listen for connections if (listen(serv_fd, 5) < 0) { _MSG("Unix domain server listen() failed: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } // Zero and set the FDs and maxfd FD_ZERO(&server_fdset); if (serv_fd > (int) max_fd) max_fd = serv_fd; // We're valid sv_valid = 1; ::chmod(socket_path.c_str(), socket_mode); _MSG("Created Unix-domain listener at " + socket_path, MSGFLAG_INFO); return 1; } void UnixDomainServer::KillConnection(int in_fd) { NetworkServer::KillConnection(in_fd); // Close the fd if (in_fd) close(in_fd); } void UnixDomainServer::Shutdown() { for (map::iterator miter = read_buf_map.begin(); miter != read_buf_map.end(); ++miter) { KillConnection(miter->first); // Reset the iterator since we cascade through the generic // netserver::killconnection which removes the ringbuf and // iterator miter = read_buf_map.begin(); if (miter == read_buf_map.end()) break; } sv_valid = 0; if (serv_fd) close(serv_fd); max_fd = 0; } int UnixDomainServer::FetchClientConnectInfo(int in_clid, void *ret_info) { struct sockaddr_un client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(client_addr)); client_len = sizeof(client_addr); if (getsockname(in_clid, (struct sockaddr *) &client_addr, &client_len) < 0) { _MSG("Unix domain server unable to get sockname for client info: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } memcpy(ret_info, &client_addr, client_len); return 1; } string UnixDomainServer::GetRemoteAddr(int in_fd) { struct sockaddr_un client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(client_addr)); client_len = sizeof(client_addr); if (getsockname(in_fd, (struct sockaddr *) &client_addr, &client_len) < 0) { _MSG("Unix domain server unable to get sockname: " + string(strerror(errno)), MSGFLAG_ERROR); return ""; } return client_addr.sun_path; } int UnixDomainServer::Accept() { int new_fd; struct sockaddr_un client_addr; #ifdef HAVE_SOCKLEN_T socklen_t client_len; #else int client_len; #endif memset(&client_addr, 0, sizeof(client_addr)); client_len = sizeof(client_addr); // Socket accept if ((new_fd = accept(serv_fd, (struct sockaddr *) &client_addr, &client_len)) < 0) { _MSG("Unix-domain server accept() failed: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } // Bail right now if we have too many connections if (FetchNumClients() >= (int) maxcli) { _MSG("Unix-domain server maximum clients (" + IntToString(maxcli) + ") already " "reached.", MSGFLAG_ERROR); close(new_fd); return -1; } // Set it to nonblocking int save_mode = fcntl(new_fd, F_GETFL, 0); fcntl(new_fd, F_SETFL, save_mode | O_NONBLOCK); if (new_fd > (int) max_fd) max_fd = new_fd; FD_SET(new_fd, &server_fdset); // There should never be overlapping fds and there should never be // remnants of an old person here, so we'll make the connection // lightweight and not do more tree searching. If this ever proves // wrong, we need to reevaluate write_buf_map[new_fd] = new RingBuffer(int_ring_len); read_buf_map[new_fd] = new RingBuffer(int_ring_len); return new_fd; } int UnixDomainServer::Validate(int in_fd) { return 1; // Perhaps check remote user? } int UnixDomainServer::ReadBytes(int in_fd) { uint8_t recv_bytes[1024]; int ret; if ((ret = read(in_fd, recv_bytes, 1024)) < 0) { if (errno == EINTR || errno == EAGAIN) return 0; _MSG("Unix domain server client read() error for " + GetRemoteAddr(in_fd) + ": " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } if (ret == 0) { _MSG("Unix domain server client read() ended for " + GetRemoteAddr(in_fd), MSGFLAG_ERROR); return -1; } if (read_buf_map[in_fd]->InsertData(recv_bytes, ret) == 0) { _MSG("Unix domain server client " + GetRemoteAddr(in_fd) + " read error, " "ring buffer full", MSGFLAG_ERROR); return -1; } return ret; } int UnixDomainServer::WriteBytes(int in_fd) { uint8_t dptr[1024]; int dlen, ret; // This can't get called on invalid fds, so save some time and // don't check write_buf_map[in_fd]->FetchPtr(dptr, 1024, &dlen); if ((ret = write(in_fd, dptr, dlen)) <= 0) { if (errno == EINTR || errno == EAGAIN) return 0; _MSG("Unix domain server: Killing client " + GetRemoteAddr(in_fd) + ", write " "error: " + string(strerror(errno)), MSGFLAG_ERROR); KillConnection(in_fd); return -1; } write_buf_map[in_fd]->MarkRead(ret); if (srvframework->BufferDrained(in_fd) < 0) { _MSG("Unix domain server: Error occured calling framework buffer drain " "notification on client " + GetRemoteAddr(in_fd), MSGFLAG_ERROR); KillConnection(in_fd); return -1; } return ret; } kismet-2013-03-R1b/dumpfile_alert.cc0000664000175000017500000000637312124602454016767 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "dumpfile_alert.h" int dumpfilealert_chain_hook(CHAINCALL_PARMS) { Dumpfile_Alert *auxptr = (Dumpfile_Alert *) auxdata; return auxptr->chain_handler(in_pack); } Dumpfile_Alert::Dumpfile_Alert() { fprintf(stderr, "FATAL OOPS: Dumpfile_Alert called with no globalreg\n"); exit(1); } Dumpfile_Alert::Dumpfile_Alert(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { char errstr[STATUS_MAX]; globalreg = in_globalreg; alertfile = NULL; type = "alert"; if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Packetchain missing before " "Dumpfile_Alert\n"); exit(1); } if (globalreg->alertracker == NULL) { fprintf(stderr, "FATAL OOPS: Alertracker missing before " "Dumpfile_Alert\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("alert")) == "" || globalreg->fatal_condition) { return; } alertfile = fopen(fname.c_str(), "w"); if (alertfile == NULL) { snprintf(errstr, STATUS_MAX, "Failed to open alert dump file '%s': %s", fname.c_str(), strerror(errno)); _MSG(errstr, MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Opened alert log file '" + fname + "'", MSGFLAG_INFO); globalreg->packetchain->RegisterHandler(&dumpfilealert_chain_hook, this, CHAINPOS_LOGGING, -100); globalreg->RegisterDumpFile(this); } Dumpfile_Alert::~Dumpfile_Alert() { globalreg->packetchain->RemoveHandler(&dumpfilealert_chain_hook, CHAINPOS_LOGGING); // Close files if (alertfile != NULL) { Flush(); fclose(alertfile); } alertfile = NULL; } int Dumpfile_Alert::Flush() { if (alertfile == NULL) return 0; fflush(alertfile); return 1; } int Dumpfile_Alert::chain_handler(kis_packet *in_pack) { if (alertfile == NULL) return 0; kis_alert_component *alrtinfo = NULL; if (in_pack->error) return 0; // Grab the alerts alrtinfo = (kis_alert_component *) in_pack->fetch(_PCM(PACK_COMP_ALERT)); if (alrtinfo == NULL) return 0; for (unsigned int x = 0; x < alrtinfo->alert_vec.size(); x++) { fprintf(alertfile, "%.24s %s %d %s %s %s %s %s\n", ctime((const time_t *) &(alrtinfo->alert_vec[x]->tm.tv_sec)), alrtinfo->alert_vec[x]->header.c_str(), alrtinfo->alert_vec[x]->channel, alrtinfo->alert_vec[x]->bssid.Mac2String().c_str(), alrtinfo->alert_vec[x]->source.Mac2String().c_str(), alrtinfo->alert_vec[x]->dest.Mac2String().c_str(), alrtinfo->alert_vec[x]->other.Mac2String().c_str(), alrtinfo->alert_vec[x]->text.c_str()); } dumped_frames++; return 1; } kismet-2013-03-R1b/dumpfile_netxml.h0000664000175000017500000000232212124602454017017 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_NETXML_H__ #define __DUMPFILE_NETXML_H__ #include "config.h" #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "dumpfile.h" #include "netracker.h" // Netxml bulk logger class Dumpfile_Netxml : public Dumpfile { public: Dumpfile_Netxml(); Dumpfile_Netxml(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Netxml(); virtual int Flush(); protected: FILE *xmlfile; }; #endif /* __dump... */ kismet-2013-03-R1b/packetsource.h0000664000175000017500000002731712124602454016326 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_H__ #define __PACKETSOURCE_H__ #include "config.h" #include #include #include "util.h" #include "uuid.h" #include "globalregistry.h" #include "messagebus.h" #include "packet.h" #include "timetracker.h" #include "gpsdclient.h" #include "configfile.h" #include "packetchain.h" #include "getopt.h" // Packet capture source superclass // This defines the methods used to go in and out of monitor mode, channel // control, and manages the lists of channels this source will hop to. // // This class will become somewhat absurdly subclassed at times. This is // a necessary evil, and better than the previous method of having tons of // random C function pointers to do work with no coherent ties to the class // itself. // // The constructor is passed the type, name, and device from the source= // line (or is manually built). // // Packet sources are not themselves pollable items. They are monitored and // called via the packetsourcetracker. // // Packet sources can exist in multiple processes: A defined but not opened // source is created before the fork() for IPC controls. // // Packet sources are registered as a new object w/ no parameters, which is // used to later generate the real packetsource via CreateSource(...) // // What that boils down to is: // 1. A subclass should provide the CreateSource(...) function, which returns // a new Subclass(...); // 2. A class should blow up on the new() operator and assign GlobalReg on the // new(GlobalRegistry *) opertor // 3. A class should provide the RegisterSources(...) function in such a way // that it works on a generic/weak instance // 4. A class should provide the AutotypeProbe(...) function in such a way // that it can be called on a generic instance (ie, one made with new() ) // It should return 1 or 0 for "claimed as this type" or "not claimed" // Forward definition of sourcetracker for the RegisterPacketSource function class Packetsourcetracker; // Return code definitions for DisableMonitor (since we want to tell the // sourcetracker how to report errors. Negative returns are always an error.) // Say nothing -- we don't do anything to a source that requires the warning // (like pcapfile) #define PACKSOURCE_UNMONITOR_RET_SILENCE 0 // We unmonitored OK but print a friendly warning anyhow #define PACKSOURCE_UNMONITOR_RET_OKWITHWARN 1 // We can't unmonitor this source, but it isn't a fatal error #define PACKSOURCE_UNMONITOR_RET_CANTUNMON 2 // Parmeters to the packet info. These get set by the packet source controller // so they need to go here. Every packet source shares these generic types, but // they may have more specifc types of their own as well. Only generic types // can be used by other components struct packet_parm { packet_parm() { fuzzy_crypt = 0; weak_dissect = 0; legal_paranoia = 0; } int fuzzy_crypt; int weak_dissect; int legal_paranoia; }; // parsed option struct packetsource_option { string opt; string val; }; // We don't do anything smart with this yet but plan ahead enum packetsource_channel_mod { channel_mod_none = 0, channel_mod_11b = 1, channel_mod_11g = 2, channel_mod_11a = 3, channel_mod_11n = 4, channel_mod_40mhz = 5 }; class KisPacketSource { public: // This is still bad, even for weak sources KisPacketSource() { fprintf(stderr, "FATAL OOPS: KisPacketSource() with no parameters\n"); exit(1); } // ------------ WEAK PACKETSOURCE ----------------- KisPacketSource(GlobalRegistry *in_globalreg) { // Nothing happens here. This just lets us new() a weak packetsource // used for calling CreateSource(...) and RegisterSources(...) // We just grab globalreg so that we can generate messages globalreg = in_globalreg; source_id = 0; } // This should call our own constructor and return a packet source of our // own type, for each subclass virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) = 0; virtual int RegisterSources(Packetsourcetracker *tracker) = 0; virtual int AutotypeProbe(string in_device) = 0; // Create a strong packet source KisPacketSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { name = in_interface; interface = in_interface; source_id = 0; type = "auto"; globalreg = in_globalreg; // Invalidate the UUID to begin with src_uuid.error = 1; dlt_mangle = 0; fcsbytes = 0; validate_fcs = 0; crc32_table = NULL; carrier_set = 0; consec_error = 0; num_packets = 0; error = 0; if (ParseOptions(in_opts) < 0) error = 1; } virtual ~KisPacketSource() { } // Parse the options -- override any existing options we have virtual int ParseOptions(vector *in_opts) { if (FetchOpt("name", in_opts) != "") name = FetchOpt("name", in_opts); if (FetchOpt("type", in_opts) != "") type = FetchOpt("type", in_opts); // Get the UUID from options if we have it, otherwise generate one // TODO: Pull from cache if (FetchOpt("uuid", in_opts) != "") { src_uuid = uuid(FetchOpt("uuid", in_opts)); if (src_uuid.error) _MSG("Invalid UUID=... on packet source " + interface + ". " "A new UUID will be generated.", MSGFLAG_ERROR); } if (src_uuid.error) { // Generate a UUID if we don't have one // This is mostly just crap. Hash the type and name, then // hash the device, and make a 6 byte field out of it to seed // the device attribute. If a subclass wants to seed this with the MAC // of the capture source in the future, thats fine too uint8_t unode[6]; uint32_t unode_hash; string combo = type + name; unode_hash = Adler32Checksum(combo.c_str(), combo.length()); memcpy(unode, &unode_hash, 4); unode_hash = Adler32Checksum(interface.c_str(), interface.length()); memcpy(&(unode[4]), &unode_hash, 2); src_uuid.GenerateTimeUUID(unode); } // if (StrLower(FetchOpt("weakvalidate", in_opts)) == "true") { if (FetchOptBoolean("weakvalidate", in_opts, 0)) { genericparms.weak_dissect = 1; _MSG("Enabling weak frame validation on packet source '" + interface + "'", MSGFLAG_INFO); } // if (StrLower(FetchOpt("validatefcs", in_opts)) == "true") { if (FetchOptBoolean("validatefcs", in_opts, 0)) { SetValidateCRC(1); _MSG("Enabling FCS frame validation on packet source '" + interface + "'", MSGFLAG_INFO); } // if (FetchOpt("fcs", in_opts) == "true") { if (FetchOptBoolean("fcs", in_opts, 0)) { _MSG("Forcing assumption that source '" + interface + "' contains " "four trailing bytes of FCS checksum data", MSGFLAG_INFO); SetFCSBytes(4); } return 1; } // Fetch the UUID virtual uuid FetchUUID() { return src_uuid; } // Data placeholder for the packet source tracker to record who we are for // much faster per-packet handling (per-frame map lookups = bad) virtual void SetSourceID(uint16_t in_id) { source_id = in_id; } virtual uint16_t FetchSourceID() { return source_id; } // Set DLT de-mangling virtual void SetDLTMangle(int in_mangle) { dlt_mangle = in_mangle; } // Mangle a packet from capture to 80211 pure + chain elements virtual int ManglePacket(kis_packet *packet, kis_datachunk *linkchunk) { return 0; } // Manage the interface virtual int EnableMonitor() = 0; virtual int DisableMonitor() = 0; // Set the card to a channel w/ a given modulation virtual int SetChannel(unsigned int in_ch) = 0; // Fetch supported channels from hardware, if we can virtual vector FetchSupportedChannels(string in_interface) { vector ret; return ret; } // Open the packet source virtual int OpenSource() = 0; virtual int CloseSource() = 0; // Get the last channel we know we set virtual int FetchChannel() { return last_channel; } virtual int FetchChannelMod() { return last_mod; } // Get the hardware channel virtual int FetchHardwareChannel() { return 0; } // Get a pollable file descriptor (usually from pcap) virtual int FetchDescriptor() = 0; // Trigger a fetch of a pending packet(s) and inject it into // the packet chain, may inject multiple packets for one call virtual int Poll() = 0; // Fetch info about how we were built virtual string FetchName() { return name; } virtual string FetchInterface() { return interface; } virtual string FetchType() { return type; } // Fetch number of packets we've processed virtual int FetchNumPackets() { return num_packets; } // Add a packet to the count (for packetsourcetracker to increment us for IPC // packets) virtual void AddPacketCount() { num_packets++; } // Pause/resume listening to this source (what this means depends on // the implementation of polling) void Pause() { paused = 1; }; void Resume() { paused = 0; }; virtual void SetFCSBytes(int in_bytes) { fcsbytes = in_bytes; } virtual unsigned int FetchFCSBytes() { return fcsbytes; } virtual void SetValidateCRC(int in_validate) { validate_fcs = in_validate; } virtual unsigned int FetchValidateCRC() { return validate_fcs; } // Set and fetch the carriers this source understands virtual void SetCarrierSet(int in_set) { carrier_set = in_set; } virtual int FetchCarrierSet() { return carrier_set; } // Generic-level per packet parameters virtual packet_parm FetchGenericParms() { return genericparms; } // Return if we're channel capable or not, used for deriving hop virtual int FetchChannelCapable() { return channel_capable; } // Return the maximum hop velocity we support (if the source is known // to have problems at higher velocities, this can be used to limit it) // By default all sources can hop as fast as the Kismet timer, 10x a second virtual int FetchChannelMaxVelocity() { return 10; } virtual int FetchSkipChanhop() { return 0; } virtual int FetchError() { return error; } virtual string FetchWarning() { return warning; } protected: virtual void FetchRadioData(kis_packet *in_packet) = 0; GlobalRegistry *globalreg; int die_on_fatal; int paused; int error; uint16_t source_id; // Name, interface string name; string interface; string type; // Unique identifier for this capture source uuid src_uuid; int dlt_mangle; // Bytes in the FCS unsigned int fcsbytes; // Are we channel capable? int channel_capable; // Are the FCS bytes coming from this source valid? // (ie, do we validate FCS and log FCS bytes?) unsigned int validate_fcs; unsigned int *crc32_table; // Total packets unsigned int num_packets; // Last channel & mod we set int last_channel; packetsource_channel_mod last_mod; int consec_error; // Set of carrier types int carrier_set; // Generic packetsource optional parameters packet_parm genericparms; // Warning state string warning; }; // Packetchain reference for packet sources to be attached to the // item captured class kis_ref_capsource : public packet_component { public: KisPacketSource *ref_source; kis_ref_capsource() { self_destruct = 1; // We're just a ptr container ref_source = NULL; } ~kis_ref_capsource() { }; }; #endif kismet-2013-03-R1b/clinetframework.cc0000664000175000017500000001440312124602454017160 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "clinetframework.h" NetworkClient::NetworkClient() { fprintf(stderr, "FATAL OOPS: Networkclient() called with no globalreg\n"); exit(-1); } NetworkClient::NetworkClient(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; cl_valid = 0; cli_fd = -1; read_buf = NULL; write_buf = NULL; connect_complete = -1; connect_cb = NULL; connect_aux = NULL; } NetworkClient::~NetworkClient() { KillConnection(); } int NetworkClient::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { int max; // fprintf(stderr, "debug - networkclient mergeset valid %d clifd %d\n", cl_valid, cli_fd); fflush(stderr); if (connect_complete == 0 && cli_fd >= 0) { // fprintf(stderr, "debug - mergeing deferred %d\n", cli_fd); FD_SET(cli_fd, out_wset); if (in_max_fd < cli_fd) max = cli_fd; else max = in_max_fd; return max; } if (in_max_fd < cli_fd && cl_valid) max = cli_fd; else max = in_max_fd; if (cl_valid) { FD_SET(cli_fd, out_rset); if ((write_buf != NULL && write_buf->FetchLen() > 0)) { FD_SET(cli_fd, out_wset); } } return max; } int NetworkClient::Poll(fd_set& in_rset, fd_set& in_wset) { int ret = 0; // fprintf(stderr, "debug - %d connect complete %d\n", cli_fd, connect_complete); if (cli_fd < 0) return 0; if (connect_complete == 0) { // printf("debug - poll query %d\n", cli_fd); if (FD_ISSET(cli_fd, &in_wset)) { int r, e; socklen_t l; e = 0; l = sizeof(int); r = getsockopt(cli_fd, SOL_SOCKET, SO_ERROR, &e, &l); // fprintf(stderr, "debug - deferred connect %d got r %d e %d l %d error %s\n", cli_fd, r, e, l, strerror(e)); if (r < 0 || e != 0) { if (connect_cb != NULL) (*connect_cb)(globalreg, e, connect_aux); // fprintf(stderr, "debug - calling killconnection\n"); KillConnection(); } else { // fprintf(stderr, "debug - %d deferred connect worked\n", cli_fd); connect_complete = 1; cl_valid = 1; if (connect_cb != NULL) (*connect_cb)(globalreg, 0, connect_aux); return 0; } } return 0; } if (!cl_valid) return 0; // Look for stuff to read if (FD_ISSET(cli_fd, &in_rset)) { // If we failed reading, die. if ((ret = ReadBytes()) < 0) { KillConnection(); return ret; } // If we've got new data, try to parse. if we fail, die. if (ret != 0 && cliframework->ParseData() < 0) { KillConnection(); return -1; } } if (cli_fd < 0 || !cl_valid) { KillConnection(); return -1; } // Look for stuff to write if (FD_ISSET(cli_fd, &in_wset)) { // fprintf(stderr, "debug - %d poll looks like something to write\n", cli_fd); // If we can't write data, die. if ((ret = WriteBytes()) < 0) KillConnection(); return ret; } return ret; } int NetworkClient::FlushRings() { if (!cl_valid) return -1; fd_set rset, wset; int max; time_t flushtime = time(0); // Nuke the fatal condition so we can track our own failures int old_fcon = globalreg->fatal_condition; globalreg->fatal_condition = 0; while ((time(0) - flushtime) < 2) { if (write_buf == NULL || (write_buf != NULL && write_buf->FetchLen() <= 0)) return 1; max = 0; FD_ZERO(&rset); FD_ZERO(&wset); max = MergeSet(max, &rset, &wset); struct timeval tm; tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { globalreg->fatal_condition = 1; return -1; } continue; } if (Poll(rset, wset) < 0 || globalreg->fatal_condition != 0) return -1; } globalreg->fatal_condition = old_fcon; return 1; } void NetworkClient::KillConnection() { // fprintf(stderr, "debug - nc killcon\n"); connect_complete = -1; // fprintf(stderr, "debug - clearing buffers %p %p\n", read_buf, write_buf); if (read_buf != NULL) delete read_buf; if (write_buf != NULL) delete write_buf; read_buf = NULL; write_buf = NULL; // fprintf(stderr, "debug - closing fd %d\n", cli_fd); if (cli_fd >= 0) close(cli_fd); cli_fd = -1; cl_valid = 0; // fprintf(stderr, "debug - clienetframework kill %p\n", cliframework); if (cliframework != NULL) cliframework->KillConnection(); return; } int NetworkClient::WriteData(void *in_data, int in_len) { if (write_buf == NULL) return 0; if (write_buf->InsertDummy(in_len) == 0) { snprintf(errstr, STATUS_MAX, "NetworkClient::WriateData no room in ring " "buffer to insert %d bytes", in_len); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } write_buf->InsertData((uint8_t *) in_data, in_len); return 1; } int NetworkClient::FetchReadLen() { if (read_buf == NULL) return 0; return (int) read_buf->FetchLen(); } int NetworkClient::ReadData(void *ret_data, int in_max, int *ret_len) { if (read_buf == NULL) return 0; read_buf->FetchPtr((uint8_t *) ret_data, in_max, ret_len); return (*ret_len); } int NetworkClient::MarkRead(int in_readlen) { if (read_buf == NULL) return 1; read_buf->MarkRead(in_readlen); return 1; } int ClientFramework::Shutdown() { int ret = 0; if (netclient != NULL) ret = netclient->FlushRings(); return ret; } kismet-2013-03-R1b/ringbuf.h0000664000175000017500000000226012124602454015260 0ustar dragorndragorn#ifndef __RINGBUF_H__ #define __RINGBUF_H__ #include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include #include #include #include #include #include #include class RingBuffer { public: RingBuffer(int in_size); ~RingBuffer(); // See if an insert would succeed (for multi-stage inserts that must // all succeed int InsertDummy(int in_len); // Add data to the ring buffer int InsertData(uint8_t *in_data, int in_len); // Fetch the length of the longest continual piece of data int FetchLen(); // Fetch the size of the buffer int FetchSize(); // Fetch the longest continual piece of data void FetchPtr(uint8_t *in_dptr, int max_len, int *in_len); // Flag bytes as read. Will only flag as many bytes are available void MarkRead(int in_len); // Change the size of the ring buffer int Resize(int in_newlen); protected: int ring_len; uint8_t *ring_data; uint8_t *ring_rptr, *ring_wptr; }; #endif kismet-2013-03-R1b/dumpfile_gpsxml.cc0000664000175000017500000001321612124602454017164 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "globalregistry.h" #include "gpscore.h" #include "dumpfile_gpsxml.h" #define GPS_VERSION 5 #define gps_track_bssid "GP:SD:TR:AC:KL:OG" int dumpfilegpsxml_chain_hook(CHAINCALL_PARMS) { Dumpfile_Gpsxml *auxptr = (Dumpfile_Gpsxml *) auxdata; return auxptr->chain_handler(in_pack); } Dumpfile_Gpsxml::Dumpfile_Gpsxml() { fprintf(stderr, "FATAL OOPS: Dumpfile_Gpsxml called with no globalreg\n"); exit(1); } Dumpfile_Gpsxml::Dumpfile_Gpsxml(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; xmlfile = NULL; last_track = 0; type = "gpsxml"; if (globalreg->sourcetracker == NULL) { fprintf(stderr, "FATAL OOPS: Sourcetracker missing before " "Dumpfile_Gpsxml\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("gpsxml")) == "" || globalreg->fatal_condition) { return; } if ((xmlfile = fopen(fname.c_str(), "w")) == NULL) { _MSG("Failed to open gpsxml log file '" + fname + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Opened gpsxml log file '" + fname + "'", MSGFLAG_INFO); // Write the XML headers fprintf(xmlfile, "\n" "\n\n"); globalreg->packetchain->RegisterHandler(&dumpfilegpsxml_chain_hook, this, CHAINPOS_LOGGING, -100); fprintf(xmlfile, "\n\n", GPS_VERSION, ctime((const time_t *) &(globalreg->timestamp.tv_sec))); string netxmlname; Dumpfile *netxmldump = globalreg->FindDumpFileType("netxml"); if (netxmldump == NULL) { netxmlname = "error-netxml-not-found"; } else{ netxmlname = netxmldump->FetchFileName(); } fprintf(xmlfile, " %s\n\n", netxmlname.c_str()); globalreg->RegisterDumpFile(this); } Dumpfile_Gpsxml::~Dumpfile_Gpsxml() { globalreg->packetchain->RemoveHandler(&dumpfilegpsxml_chain_hook, CHAINPOS_LOGGING); // Close files if (xmlfile != NULL) { fprintf(xmlfile, "\n"); Flush(); fclose(xmlfile); } xmlfile = NULL; } int Dumpfile_Gpsxml::Flush() { if (xmlfile == NULL) return 0; fflush(xmlfile); return 1; } int Dumpfile_Gpsxml::chain_handler(kis_packet *in_pack) { kis_gps_packinfo *gpsinfo = NULL; kis_ieee80211_packinfo *eight11 = NULL; kis_layer1_packinfo *radio = NULL; if (in_pack->error) return 0; // No GPS info, no worky if ((gpsinfo = (kis_gps_packinfo *) in_pack->fetch(_PCM(PACK_COMP_GPS))) == NULL) { return 0; } // Obviously no point in logging when theres no valid lock if (gpsinfo->gps_fix < 2) { return 0; } // If all we're doing is logging the GPS info... if ((eight11 = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211))) == NULL) { // If we're only logging GPS track data, only do it once a second // (plugins, specifically non-dot11 PHYs, may have GPS tagged packets // with no eight11 record) if (last_track == globalreg->timestamp.tv_sec) return 0; last_track = globalreg->timestamp.tv_sec; fprintf(xmlfile, " ts.tv_sec, (long int) in_pack->ts.tv_usec, gpsinfo->lat, gpsinfo->lon, gpsinfo->spd, gpsinfo->heading, gpsinfo->gps_fix); if (gpsinfo->gps_fix >= 3) fprintf(xmlfile, " alt=\"%f\"", gpsinfo->alt); if (gpsinfo->hdop != 0 || gpsinfo->vdop != 0) fprintf(xmlfile, " hdop=\"%f\" vdop=\"%f\"", gpsinfo->hdop, gpsinfo->vdop); fprintf(xmlfile, "/>\n"); dumped_frames++; return 1; } // Don't log errored eight11 packets if (eight11->corrupt || eight11->type == packet_unknown) return 0; // Otherwise we want to try to log the signal levels too radio = (kis_layer1_packinfo *) in_pack->fetch(_PCM(PACK_COMP_RADIODATA)); fprintf(xmlfile, " bssid_mac.Mac2String().c_str(), eight11->source_mac.Mac2String().c_str(), (long int) in_pack->ts.tv_sec, (long int) in_pack->ts.tv_usec, gpsinfo->lat, gpsinfo->lon, gpsinfo->spd, gpsinfo->heading, gpsinfo->gps_fix); if (gpsinfo->gps_fix >= 3) fprintf(xmlfile, " alt=\"%f\"", gpsinfo->alt); if (gpsinfo->hdop != 0 || gpsinfo->vdop != 0) fprintf(xmlfile, " hdop=\"%f\" vdop=\"%f\"", gpsinfo->hdop, gpsinfo->vdop); if (radio != NULL) { if (radio->signal_rssi != 0) { fprintf(xmlfile, " signal_rssi=\"%d\" noise_rssi=\"%d\"", radio->signal_rssi, radio->noise_rssi); } if (radio->signal_dbm != 0) { fprintf(xmlfile, " signal_dbm=\"%d\" noise_dbm=\"%d\"", radio->signal_dbm, radio->noise_dbm); } } fprintf(xmlfile, "/>\n"); dumped_frames++; return 1; } kismet-2013-03-R1b/tcpserver.h0000664000175000017500000000613612124602454015647 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TCPSERVER_H__ #define __TCPSERVER_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuf.h" #include "messagebus.h" #include "timetracker.h" #include "netframework.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif // Arbitrary 64k ring by default #define SRV_RING_LEN (65536) class TcpServer : public NetworkServer { public: // IP filtering struct client_ipfilter { in_addr network; in_addr mask; }; TcpServer(); TcpServer(GlobalRegistry *in_globalreg); virtual ~TcpServer(); // Set up the TCP socket and listening virtual int SetupServer(short int in_port, unsigned int in_maxcli, string in_bindaddr, string in_filterstr); // Enable server virtual int EnableServer(); // Kill a connection by client ID virtual void KillConnection(int in_fd); // Fetch the info for a client id virtual int FetchClientConnectInfo(int in_clid, void *ret_info); // Shutdown the entire server virtual void Shutdown(); // Fetch the port # virtual short int FetchPort() { return port; } virtual string GetRemoteAddr(int in_fd); // Set the size of ring buffers. This ONLY affects new connections, not // existing! virtual void SetRingSize(int in_sz); protected: // Accept the connection TCP-level virtual int TcpAccept(); // Broker various acceptance stuff virtual int Accept(); // Validate a connection by IP virtual int ValidateIPFilter(int in_fd); // Validate a connection virtual int Validate(int in_fd); // Read pending bytes from the socket into the read ring buffer virtual int ReadBytes(int in_fd); // Write bytes from the write ring buffer to the socket virtual int WriteBytes(int in_fd); // IP filtering vector ipfilter_vec; // Server info char hostname[MAXHOSTNAMELEN]; short int port; unsigned int maxcli; string bindaddr; // Is it configured? int sv_configured; struct sockaddr_in serv_sock; // Ring length, if we resize it int int_ring_len; }; #endif kismet-2013-03-R1b/kis_panel_frontend.h0000664000175000017500000001723012124602454017473 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_FRONTEND_H__ #define __KIS_PANEL_FRONTEND_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include #include #include #include #include "uuid.h" #include "pollable.h" #include "messagebus.h" #include "kis_panel_widgets.h" #include "kis_panel_windows.h" #include "kis_clinetframe.h" #include "kis_panel_plugin.h" #include "configfile.h" #include "popenclient.h" #include "text_cliframe.h" #define WIN_CENTER(h, w) (LINES / 2) - ((h) / 2), (COLS / 2) - ((w) / 2), (h), (w) class KisPanelInterface; // Our specialized actual kismet frontend // Most of the drawing is inherited from the generic case panel interface, // but we need to add our own tracking systems and such here. // // This also implements all the hooks which get linked to the clients to // process protocols. #define KPI_ADDCLI_CB_PARMS GlobalRegistry *globalreg, KisNetClient *netcli, \ int add, void *auxptr typedef void (*KPI_AddCli_Callback)(KPI_ADDCLI_CB_PARMS); // Plugin version information, v1 // This holds revision information for the KISMET THE PLUGIN WAS COMPILED WITH, // NOT THE PLUGIN VERSION (plugin version is passed in the info struct!) struct panel_plugin_revision { // V1 data // Versioned for possible updates to the version api int version_api_revision; string major; string minor; string tiny; // End V1 data }; #define KIS_PANEL_PLUGIN_VREVISION 1 // Plugin revision call. If the kis_plugin_revision symbol is available in the plugin, // then it will be passed an allocated plugin_revision struct, with the version_api_rev // set appropriately. Plugins MUST ONLY use fields in the negotiated plugin version // record. This record is not expected to change significantly over time, BUT IT MAY, // should it become necessary to add more complex data. typedef void (*panel_plugin_revisioncall)(panel_plugin_revision *); class KisPanelInterface : public PanelInterface { public: KisPanelInterface(); KisPanelInterface(GlobalRegistry *in_globalreg); virtual ~KisPanelInterface(); virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); virtual void Shutdown(); virtual void AddPanel(Kis_Panel *in_panel); virtual void KillPanel(Kis_Panel *in_panel); virtual int LoadPreferences(); virtual int SavePreferences(); // Connect to a network client & register callbacks for when one is added virtual int AddNetClient(string in_host, int in_reconnect); virtual void RemoveNetClient(); virtual int Add_NetCli_AddCli_CB(KPI_AddCli_Callback in_cb, void *in_aux); virtual void Remove_Netcli_AddCli_CB(int in_cbref); virtual void Remove_All_Netcli_Conf_CB(CliConf_Callback in_cb); virtual void Remove_All_Netcli_Cmd_CB(CliCmd_Callback in_cb, void *in_aux); virtual int Remove_All_Netcli_ProtoHandler(string in_proto, CliProto_Callback in_cb, void *in_aux); // Fetch the client KisNetClient *FetchNetClient() { return network_client; } // Are we connected to a client? int FetchNetConnected() { if (network_client && network_client->Valid()) return 1; return 0; } // Configured client callback virtual void NetClientConfigure(KisNetClient *in_cli, int in_recon); // Bring up a modal alert (may be queued if an alert is already displayed) virtual void RaiseAlert(string in_title, string in_text); // Queue a modal panel, we only display one modal panel at a time. // Alerts are modal, prompt boxes should almost always be considered modal. virtual void QueueModalPanel(Kis_Panel *in_panel); // We track cards at the interface level because we need instant feedback on them // without waiting for individual widgets to do their own activate and poll, though // a widget CAN still directly talk the SOURCE protocol if it needs to struct knc_card { // Last time this record got updated time_t last_update; // Hash for the UUID, used as a placeholder in the select table since // we need just an int there. We hope this never collides, and if it // does, we'll figure out some other way to deal with this uint32_t uuid_hash; string interface; string type; string name; // We need a copy of this anyhow uuid carduuid; int channel; int packets; int hopping; int hopvelocity; int dwell; struct timeval hop_tm; // Store as a string since we don't necessarily care string channellist; // Are we in an error state? int error; // Do we have a warning? string warning; }; struct knc_alert { struct timeval tv; string alertname; mac_addr bssid, source, dest, other; int channel; string text; }; // Internal parser for ALERT proto void proto_ALERT(CLIPROTO_CB_PARMS); vector *FetchAlertVec() { return &alert_vec; } // Internal parser for the CARD proto, linked to the callback void proto_SOURCE(CLIPROTO_CB_PARMS); // Fetch the list of cards from the system map *FetchNetCardMap(); void proto_INFO(CLIPROTO_CB_PARMS); struct addcli_cb_rec { int refnum; KPI_AddCli_Callback cb; void *auxptr; }; void LoadPlugin(string in_fname, string in_objname); vector *FetchPluginVec() { return &plugin_vec; } void ScanPlugins(); void LoadPlugins(); Kis_Main_Panel *FetchMainPanel() { return mainp; } // Public so we don't have pointless wrappers ConfigFile *prefs; Kis_Panel_Color colors; // Interface level since it's independent of the UI void SpawnServer(string in_parm); void SpawnServer(); void KillServer(); // These need to be exposed to the callbacks for clean shutdown TextCliFrame *FetchServerFramework() { return server_framework; } PopenClient *FetchServerPopen() { return server_popen; } vector *FetchServerConsole() { return &server_console; } void ResetWarnAllClear() { warned_cleared = 1; warned_all_errors_consec = 0; warned_all_errors = time(0); } protected: int shutdown_mode; // Only allow one server, I don't think anyone really used multiple // simultaneous servers and if they did, too bad, it introduced way too // much hassle KisNetClient *network_client; // Map of UUIDs of sources to representations map netcard_map; // Alerts vector alert_vec; int addcb_ref; vector addclicb_vec; // Map of all the settings and prefs vector plugin_vec; KisPanelPluginData plugdata; Kis_Main_Panel *mainp; // Server monitoring stuff TextCliFrame *server_framework; PopenClient *server_popen; string server_parm; vector server_console; int server_text_cb; // Have we yelled at the user for not having any sources enabled? int warned_no_sources; // Or are they all broken? int warned_all_errors, warned_all_errors_consec, warned_cleared; vector modal_vec; }; #endif // panel #endif // header kismet-2013-03-R1b/packetsource_bsdrt.cc0000664000175000017500000003073012124602454017653 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef SYS_NETBSD #include #include #include #include #include #include #endif #if (defined(HAVE_LIBPCAP) && (defined(SYS_OPENBSD) || defined(SYS_NETBSD) || \ defined(SYS_FREEBSD))) #include #include #include #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #include "packetsource_bsdrt.h" #include "packetsourcetracker.h" Radiotap_BSD_Controller::Radiotap_BSD_Controller(GlobalRegistry *in_globalreg, string in_dev) { globalreg = in_globalreg; dev = in_dev; sock = -1; } Radiotap_BSD_Controller::~Radiotap_BSD_Controller() { if (sock >= 0) close(sock); } int Radiotap_BSD_Controller::MonitorEnable() { // Get current state (void) GetMediaOpt(prev_options, prev_mode); (void) Get80211(IEEE80211_IOC_CHANNEL, prev_chan, 0, NULL); (void) GetIfFlags(prev_flags); // Enter monitor mode, set the specified channel, enable promisc // reception, force the interface up, set bpf if (SetMediaOpt(IFM_IEEE80211_MONITOR, IFM_AUTO) == 0) { _MSG("BSD interface set media command failed. The drivers for this device " "may not support radiotap operation.", MSGFLAG_FATAL); return 0; } #if 0 if (Set80211(IEEE80211_IOC_CHANNEL, prev_chan, 0, NULL) < 0) { _MSG("BSD interface set channel operation failed, attempting to restore " "previous operation mode and terminate", MSGFLAG_FATAL); globalreg->fatal_condition = 1; (void) SetMediaOpt(prev_options, prev_mode); return 0; } #endif #if defined(SYS_FREEBSD) if (SetIfFlags(prev_flags | IFF_PPROMISC | IFF_UP) == 0) { #elif defined(SYS_OPENBSD) || defined(SYS_NETBSD) if (SetIfFlags(prev_flags | IFF_PROMISC | IFF_UP) == 0) { #endif _MSG("BSD interface set promisc operation failed, attempting to restore " "previous operation mode and terminate", MSGFLAG_FATAL); globalreg->fatal_condition = 1; (void) Set80211(IEEE80211_IOC_CHANNEL, prev_chan, 0, NULL); (void) SetMediaOpt(prev_options, prev_mode); return 0; } return 1; } int Radiotap_BSD_Controller::MonitorReset() { (void) SetIfFlags(prev_flags); // Reset the channel before switching modes // (void) Set80211(IEEE80211_IOC_CHANNEL, prev_chan, 0, NULL); (void) SetMediaOpt(prev_options, prev_mode); return 1; } int Radiotap_BSD_Controller::ChangeChannel(int in_ch) { if (Set80211(IEEE80211_IOC_CHANNEL, in_ch, 0, NULL) == 0) { _MSG("BSD interface control failed to set channel on '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } return 1; } int Radiotap_BSD_Controller::GetMediaOpt(int& options, int& mode) { struct ifmediareq ifmr; if (CheckSocket() == 0) return false; memset(&ifmr, 0, sizeof(ifmr)); strncpy(ifmr.ifm_name, dev.c_str(), sizeof(ifmr.ifm_name)); // Go through the motions of reading all supported media because // we need to know both the current and top-level media types if (ioctl(sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { _MSG("BSD interface control failed to get media for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } options = IFM_OPTIONS(ifmr.ifm_current); mode = IFM_MODE(ifmr.ifm_current); return 1; } int Radiotap_BSD_Controller::SetMediaOpt(int options, int mode) { struct ifmediareq ifmr; struct ifreq ifr; int *mwords; if (CheckSocket() == 0) return 0; memset(&ifmr, 0, sizeof(ifmr)); strncpy(ifmr.ifm_name, dev.c_str(), sizeof(ifmr.ifm_name)); // Go through to motions of reading all the media to get current and // top-level types if (ioctl(sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { _MSG("BSD interface control failed to get media for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } if (ifmr.ifm_count == 0) { _MSG("BSD interface control failed to get media (no media types?) " "for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } mwords = new int[ifmr.ifm_count]; if (mwords == NULL) { _MSG("BSD interface control cannot malloc interface array, out of " "memory or other badness.", MSGFLAG_PRINTERROR); return 0; } ifmr.ifm_ulist = mwords; if (ioctl(sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { _MSG("BSD interface control failed to get media " "for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } delete[] mwords; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev.c_str(), sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr.ifm_current &~ IFM_OMASK) | options; ifr.ifr_media = (ifr.ifr_media &~ IFM_MMASK) | IFM_MAKEMODE(mode); if (ioctl(sock, SIOCSIFMEDIA, (caddr_t) &ifr) < 0) { _MSG("BSD interface control failed to set media " "for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } return 1; } #if defined(SYS_OPENBSD) || defined(SYS_NETBSD) // Simple 802.11 ioctl replacement for open/net, only used for channsel set/get. // This should be rewritten to be *BSD agnostic int Radiotap_BSD_Controller::Get80211(int type, int& val, int len, uint8_t *data) { struct ieee80211chanreq channel; if (CheckSocket() == 0) return 0; memset(&channel, 0, sizeof(channel)); strlcpy(channel.i_name, dev.c_str(), sizeof(channel.i_name)); if (ioctl(sock, SIOCG80211CHANNEL, (caddr_t) &channel) < 0) { _MSG("BSD interface control failed to get channel info for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } val = channel.i_channel; return 1; } int Radiotap_BSD_Controller::Set80211(int type, int val, int len, uint8_t *data) { struct ieee80211chanreq channel; if (CheckSocket() == 0) return 0; strlcpy(channel.i_name, dev.c_str(), sizeof(channel.i_name)); channel.i_channel = (uint16_t) val; if (ioctl(sock, SIOCS80211CHANNEL, (caddr_t) &channel) == -1) { ostringstream osstr; osstr << "BSD interface control failed to set channel " << val << " for " "interface '" << dev << "': " << strerror(errno); _MSG(osstr.str(), MSGFLAG_ERROR); return 0; } return 1; } #elif defined(SYS_FREEBSD) /* Freebsd has a generic 802.11 ioctl */ int Radiotap_BSD_Controller::Get80211(int type, int& val, int len, uint8_t *data) { struct ieee80211req ireq; if (CheckSocket() == 0) return 0; memset(&ireq, 0, sizeof(ireq)); strncpy(ireq.i_name, dev.c_str(), sizeof(ireq.i_name)); ireq.i_type = type; ireq.i_len = len; ireq.i_data = data; if (ioctl(sock, SIOCG80211, &ireq) < 0) { _MSG("BSD interface control failed to get 80211 info for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } val = ireq.i_val; return 1; } int Radiotap_BSD_Controller::Set80211(int type, int val, int len, uint8_t *data) { struct ieee80211req ireq; if (CheckSocket() == 0) return 0; memset(&ireq, 0, sizeof(ireq)); strncpy(ireq.i_name, dev.c_str(), sizeof(ireq.i_name)); ireq.i_type = type; ireq.i_val = val; ireq.i_len = len; ireq.i_data = data; if (ioctl(sock, SIOCS80211, &ireq) < 0) { _MSG("BSD interface control failed to set 80211 info for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); } return 1; } #endif int Radiotap_BSD_Controller::GetIfFlags(int& flags) { struct ifreq ifr; if (CheckSocket() == 0) return 0; strncpy(ifr.ifr_name, dev.c_str(), sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { _MSG("BSD interface control failed to get interface flags for '" + dev + "': " + strerror(errno), MSGFLAG_ERROR); return 0; } #if defined(SYS_FREEBSD) flags = (ifr.ifr_flags & 0xFFFF) | (ifr.ifr_flagshigh << 16); #elif defined(SYS_OPENBSD) || defined(SYS_NETBSD) flags = ifr.ifr_flags; #endif return 1; } int Radiotap_BSD_Controller::SetIfFlags(int flags) { struct ifreq ifr; if (CheckSocket() == 0) return 0; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev.c_str(), sizeof (ifr.ifr_name)); #if defined(SYS_FREEBSD) ifr.ifr_flags = flags & 0xffff; ifr.ifr_flagshigh = flags >> 16; #elif defined(SYS_OPENBSD) || defined(SYS_NETBSD) ifr.ifr_flags = flags; #endif if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { _MSG("BSD interface control failed to set interface flags for '" + dev + "': " + strerror(errno), MSGFLAG_PRINTERROR); return 0; } return 1; } int Radiotap_BSD_Controller::CheckSocket() { if (sock < 0) { sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { _MSG("BSD interface control failed to create AF_INET socket", MSGFLAG_ERROR); return 0; } } return 1; } int PacketSource_BSDRT::AutotypeProbe(string in_device) { return 0; } int PacketSource_BSDRT::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("radiotap_bsd_ag", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("radiotap_bsd_a", this, "IEEE80211a", 1); tracker->RegisterPacketProto("radiotap_bsd_g", this, "IEEE80211b", 1); tracker->RegisterPacketProto("radiotap_bsd", this, "IEEE80211b", 1); tracker->RegisterPacketProto("bsd", this, "IEEE80211b", 1); return 1; } int PacketSource_BSDRT::EnableMonitor() { if (bsdcon->MonitorEnable() == 0) { delete bsdcon; _MSG("Unable to enable monitor mode on '" + interface + "'.", MSGFLAG_PRINTERROR); return -1; } return 0; } int PacketSource_BSDRT::DisableMonitor() { if (bsdcon == NULL) { _MSG("BSD interface controller left in unknown mode for " + interface + ". Interface cannot be cleanly returned to previous settings and " "may be left in an unusable state.", MSGFLAG_PRINTERROR); return -1; } if (bsdcon->MonitorReset() == 0) { delete bsdcon; bsdcon = NULL; _MSG("Failed to reset wireless mode of '" + interface + "' to stored values. " "It may be left in an unusable state.", MSGFLAG_PRINTERROR); return -1; } delete bsdcon; bsdcon = NULL; return PACKSOURCE_UNMONITOR_RET_OKWITHWARN; } int PacketSource_BSDRT::SetChannel(unsigned int in_ch) { if (bsdcon == NULL) { _MSG("PacketSource_BSD channel set called while bsdcon controller is NULL", MSGFLAG_PRINTERROR); return -1; } if (bsdcon->ChangeChannel(in_ch) == 0) { consec_error++; if (consec_error > 5) { return -1; } return 0; } consec_error = 0; return 1; } int PacketSource_BSDRT::CheckDLT(int dlt) { int found = 0; int i, n, *dl; n = pcap_list_datalinks(pd, &dl); for (i = 0; i < n; i++) { if (dl[i] == dlt) { found = 1; break; } } free(dl); return found; } int PacketSource_BSDRT::FetchHardwareChannel() { int chan; Radiotap_BSD_Controller bsdcon(globalreg, interface); if (bsdcon.Get80211(IEEE80211_IOC_CHANNEL, chan, 0, NULL) == 0) { return -1; } return chan; } void PacketSource_BSDRT::FetchRadioData(kis_packet *in_packet) { // Nothing to do here return; } int PacketSource_BSDRT::DatalinkType() { char errstr[STATUS_MAX] = ""; datalink_type = pcap_datalink(pd); // Known good pcap generic header types if (datalink_type == DLT_PRISM_HEADER || datalink_type == DLT_IEEE802_11_RADIO || datalink_type == DLT_IEEE802_11_RADIO_AVS || datalink_type == DLT_IEEE802_11 || datalink_type == DLT_PPI) return 1; // Blow up if we're not valid 802.11 headers // Need to not blow up on en10mb? Override. if (datalink_type == DLT_EN10MB) { snprintf(errstr, STATUS_MAX, "pcap reported netlink type 1 (EN10MB) for %s. " "This probably means you're not in RFMON mode or your drivers are " "reporting a bad value. Make sure you have the correct drivers " "and that entering monitor mode succeeded.", interface.c_str()); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return 0; } else { snprintf(errstr, STATUS_MAX, "Unknown link type %d reported. Continuing on " "blindly and hoping we get something useful... This is ALMOST " "CERTIANLY NOT GOING TO WORK RIGHT", datalink_type); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); } return 1; } #endif kismet-2013-03-R1b/iwcontrol.h0000664000175000017500000000533612124602454015653 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __IWCONTROL_H__ #define __IWCONTROL_H__ #include "config.h" #include #include #include #include #include "util.h" #ifdef HAVE_LINUX_WIRELESS #define IW_MAX_PRIV_DEF 256 // Wireless extentions monitor mode number #define LINUX_WLEXT_MONITOR 6 // Wireless extentions master mode #define LINUX_WLEXT_MASTER 3 // Max version of wext we know about #define WE_MAX_VERSION 22 // remove the SSID of the device. Some cards seem to need this. int Iwconfig_Set_SSID(const char *in_dev, char *errstr, const char *in_essid); int Iwconfig_Get_SSID(const char *in_dev, char *errstr, char *in_essid); // Get the name int Iwconfig_Get_Name(const char *in_dev, char *errstr, char *in_name); // Set a private ioctl that takes 1 or 2 integer parameters // A return of -2 means no privctl found that matches, so that the caller // can return a more detailed failure message // // This DOES NOT handle sub-ioctls. I've never seen them used. If this // blows up some day on some driver, I'll fix it. int Iwconfig_Set_IntPriv(const char *in_dev, const char *privcmd, int val1, int val2, char *errstr); // Get a single-param private ioctl. This will have to be changed if we // ever need to remember a two-value privioctl, but hopefully nothing // will. int Iwconfig_Get_IntPriv(const char *in_dev, const char *privcmd, int *val, char *errstr); // Fetch levels int Iwconfig_Get_Levels(const char *in_dev, char *in_err, int *level, int *noise); // Fetch channel int Iwconfig_Get_Channel(const char *in_dev, char *errstr); // Set channel int Iwconfig_Set_Channel(const char *in_dev, int in_ch, char *errstr); // Get/set mode int Iwconfig_Get_Mode(const char *in_dev, char *errstr, int *in_mode); int Iwconfig_Set_Mode(const char *in_dev, char *errstr, int in_mode); // Info conversion int FloatChan2Int(float in_chan); int Iwconfig_Get_Chanlist(const char *interface, char *errstr, vector *chan_list); #endif #endif kismet-2013-03-R1b/kismet_capture.cc0000664000175000017500000002420212124602454017001 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "version.h" #include #include #include #include #include "getopt.h" #include #include #include #include #include #include "util.h" #include "globalregistry.h" #include "messagebus.h" #include "packetsource.h" #include "packetsource_bsdrt.h" #include "packetsource_pcap.h" #include "packetsource_wext.h" #include "packetsource_drone.h" #include "packetsource_ipwlive.h" #include "packetsource_airpcap.h" #include "packetsource_darwin.h" #include "packetsourcetracker.h" #include "dumpfile.h" #include "dumpfile_tuntap.h" #include "timetracker.h" #include "netframework.h" #include "tcpserver.h" // Include the stubbed empty netframe code #include "kis_netframe.h" #include "kis_droneframe.h" #include "ipc_remote.h" #ifdef HAVE_CAPABILITY #include #include #endif #ifndef exec_name char *exec_name; #endif // One of our few globals in this file int glob_linewrap = 1; int glob_silent = 0; // Ultimate registry of global components GlobalRegistry *globalreg = NULL; int Usage(char *argv) { printf("Usage: None\n"); printf("This is a helper binary meant to be integrated with kismet_server for\n" "controlling packet sources. It is not useful when called directly.\n"); exit(1); } void CatchShutdown(int) { if (globalreg->sourcetracker) globalreg->sourcetracker->StopSource(0); globalreg->rootipc->ShutdownIPC(NULL); exit(1); } void DropPrivCapabilities() { #ifdef HAVE_CAPABILITY // Modeled from wireshark dumpcap // Enable NET_ADMIN and NET_RAW to get some control and capture abilities, // then drop our SUID privs cap_value_t cap_list[2] = { CAP_NET_ADMIN, CAP_NET_RAW }; int cl_len = sizeof(cap_list) / sizeof(cap_value_t); cap_t caps = cap_init(); if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { _MSG("kismet_capture prctl() failed " + string(strerror(errno)), MSGFLAG_ERROR); } cap_set_flag(caps, CAP_PERMITTED, cl_len, cap_list, CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, cl_len, cap_list, CAP_SET); if (cap_set_proc(caps)) { _MSG("kismet_capture cap_set_proc() failed: " + string(strerror(errno)), MSGFLAG_ERROR); } cap_set_flag(caps, CAP_EFFECTIVE, cl_len, cap_list, CAP_SET); if (cap_set_proc(caps)) { _MSG("kismet_capture cap_set_proc() failed: " + string(strerror(errno)), MSGFLAG_ERROR); } cap_free(caps); #endif } // When we've finished starting up on the server side (like if we've been sent // the tuntap information) this will let us drop privs int kc_startup_ipc(IPC_CMD_PARMS) { if (parent) return 0; DropPrivCapabilities(); // Send generic ack return 0; } int main(int argc, char *argv[], char *envp[]) { exec_name = argv[0]; char errstr[STATUS_MAX]; // Catch the interrupt handler to shut down signal(SIGINT, CatchShutdown); signal(SIGTERM, CatchShutdown); signal(SIGHUP, CatchShutdown); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); // Start filling in key components of the globalregistry globalreg = new GlobalRegistry; globalreg->version_major = VERSION_MAJOR; globalreg->version_minor = VERSION_MINOR; globalreg->version_tiny = VERSION_TINY; globalreg->revision = REVISION; globalreg->revdate = REVDATE; // Copy for modules globalreg->argc = argc; globalreg->argv = argv; globalreg->envp = envp; // Create the message bus globalreg->messagebus = new MessageBus; // Create the IPC system globalreg->rootipc = new RootIPCRemote(globalreg, "root capture control"); if (globalreg->rootipc->SetChildExecMode(argc, argv) < 0) { fprintf(stderr, "FATAL: Failed to attach to parent IPC. Do not run this " "directly from the command line, it is meant to be run inside the " "Kismet IPC framework.\n"); exit(1); } // Open the FD passing descriptor globalreg->rootipc->OpenFDPassSock(); // Add the IPC messagebus IPC_MessageClient *ipccli = new IPC_MessageClient(globalreg, globalreg->rootipc); globalreg->messagebus->RegisterClient(ipccli, MSGFLAG_ALL); // We can't make this work with tuntap right now // DropPrivCapabilities(); // Allocate some other critical stuff globalreg->timetracker = new Timetracker(globalreg); // Create the stubbed network/protocol server globalreg->kisnetserver = new KisNetFramework(globalreg); // Create the packet chain - PST uses it to grab frames to send to IPC globalreg->packetchain = new Packetchain(globalreg); if (globalreg->fatal_condition) CatchShutdown(-1); // Create the packetsourcetracker globalreg->sourcetracker = new Packetsourcetracker(globalreg); if (globalreg->fatal_condition) CatchShutdown(-1); globalreg->sourcetracker->RegisterIPC(globalreg->rootipc, 1); // Add the startup command globalreg->rootipc->RegisterIPCCmd(&kc_startup_ipc, NULL, NULL, "STARTUP"); // Add the packet sources #ifdef USE_PACKETSOURCE_PCAPFILE if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Pcapfile(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WEXT if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Wext(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFI if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Madwifi(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFING if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_MadwifiNG(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WRT54PRISM if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Wrt54Prism(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DRONE if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Drone(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_BSDRT if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_BSDRT(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_IPWLIVE if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Ipwlive(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_AIRPCAP if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_AirPcap(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DARWIN if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Darwin(globalreg)) < 0 || globalreg->fatal_condition) CatchShutdown(-1); #endif #ifndef SYS_CYGWIN // Prep the tuntap new Dumpfile_Tuntap(globalreg); if (globalreg->fatal_condition) CatchShutdown(-1); #endif if (globalreg->fatal_condition) CatchShutdown(-1); // If we're ready to go, send a root synced packet globalreg->rootipc->SyncRoot(); // printf("debug - kismet capture sending syncroot\n"); int max_fd = 0; fd_set rset, wset; struct timeval tm; time_t ipc_spin_start = time(0); // Wait for the return sync before sending anything more while (1) { // printf("debug - capture startup loop\n"); FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalreg->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalreg->subsys_pollable_vec.size(); x++) max_fd = globalreg->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } for (unsigned int x = 0; x < globalreg->subsys_pollable_vec.size(); x++) { if (globalreg->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalreg->fatal_condition) { // printf("debug - capture got a fail in startup poll\n"); CatchShutdown(-1); } } if (globalreg->rootipc->FetchRootIPCSynced() > 0) break; if (time(0) - ipc_spin_start > 2) break; } // printf("debug - capture got out of startup loop\n"); if (globalreg->rootipc->FetchRootIPCSynced() <= 0) { _MSG("kismet_capture pid " + IntToString(getpid()) + " failed to get " "a sync from kismet_server in a timely fashion, something is wrong. " "Continuing, but this may lead to additional errors", MSGFLAG_ERROR); } else { _MSG("kismet_capture pid " + IntToString(getpid()) + " synced with Kismet " "server, starting service loop", MSGFLAG_INFO); } // Core loop while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalreg->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalreg->subsys_pollable_vec.size(); x++) max_fd = globalreg->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } globalreg->timetracker->Tick(); for (unsigned int x = 0; x < globalreg->subsys_pollable_vec.size(); x++) { if (globalreg->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalreg->fatal_condition) { CatchShutdown(-1); } } } CatchShutdown(-1); } kismet-2013-03-R1b/cygwin_utils.cc0000664000175000017500000001402112124602454016500 0ustar dragorndragorn/* This file was written by Loris Degioanni, and is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef SYS_CYGWIN #include #include #include #include #define HANDLE2FD_INTERNAL #include "cygwin_utils.h" // // There are two main parameters that can be used to tune the WinPcap performance: // mintocopy and the read event timeout. // // Mintocopy is the minimum amount of data in the kernel buffer that causes the read event to // be set by the driver. A small mintocopy means good responisiveness but high CPU load. A big // mintocopy forces bigger kernel buffering, at the cost of low responsiveness // // The read event timeout can be used to check the availability of data once in a while. When the // timeout expires, the application will unblock and perform a read, even if the driver doesn't // have mintocopy bytes in the buffer. // // Using the timeout prevents kismet from sitting forver before processing the packets when traffic // is low, but can cause empty reads. Therefore, we set it to a large enough interval that the // performace hit is neglibile. // #define THREAD_WAIT_INTERVAL 500 Handle2Fd::Handle2Fd() { NHandles = 1; ThreadAlive = 1; PipeSignalled = 0; WaitThreadHandle = NULL; FirstFdSet = 1; InitializeCriticalSection(&PipeCs); } Handle2Fd::~Handle2Fd() { // Kill the thread and wait until he's returned ThreadAlive = 0; SetEvent(WinHandles[0]); WaitForSingleObject(WaitThreadHandle, INFINITE); } // Set the pipe fd so that it unblocks select void Handle2Fd::SetPipe() { int val; EnterCriticalSection(&PipeCs); if (!PipeSignalled) { write(PipeFds[1], &val, sizeof(val)); fdatasync(PipeFds[1]); PipeSignalled = 1; } LeaveCriticalSection(&PipeCs); } // Reset the pipe fd so that it blocks select void Handle2Fd::ResetPipe() { int val; EnterCriticalSection(&PipeCs); // First, write something to be sure the read will not block write(PipeFds[1], &val, sizeof(val)); fdatasync(PipeFds[1]); // Second, we drain the pipe while(read(PipeFds[0], ResetBuf, sizeof(ResetBuf)) == sizeof(ResetBuf)); // Third, we clear the signalled flag PipeSignalled = 0; LeaveCriticalSection(&PipeCs); } // This thread handles asynchronously waiting on the Windows events. // It signals the pipe if one or more events are set. DWORD WINAPI Handle2Fd::WaitThread(LPVOID lpParameter) { DWORD WaitRes; Handle2Fd* This = (Handle2Fd*)lpParameter; while (This->ThreadAlive) { WaitRes = WaitForMultipleObjects(This->NHandles, This->WinHandles, FALSE, THREAD_WAIT_INTERVAL); // Event number 0 is the service event used to kill the thread if (WaitRes != WAIT_OBJECT_0) { ResetEvent(This->ReadEvent); This->SetPipe(); WaitForSingleObject(This->ReadEvent, INFINITE); } } return 1; } // Mark a signal as read void Handle2Fd::Signalread() { SetEvent(ReadEvent); } // Activate this instance of the Handle2Fd class. // This involves creating the pipe, the service event and the support thread int Handle2Fd::Activate() { // Create the pipe if (pipe(PipeFds) != 0) { return -1; } // The fd stars in non-signaled state ResetPipe(); // Create the event for pipe control, and put it in our list WinHandles[0] = CreateEvent(NULL, TRUE, FALSE, NULL); if (!WinHandles[0]) { close(PipeFds[0]); close(PipeFds[1]); return -1; } // Create the event that will syncronize us with the read loop ReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ReadEvent) { close(PipeFds[0]); close(PipeFds[1]); CloseHandle(WinHandles[0]); return -1; } // Start the thread that does the handle checking if ((WaitThreadHandle = CreateThread( NULL, 0, Handle2Fd::WaitThread, this, 0, NULL)) == NULL) { close(PipeFds[0]); close(PipeFds[1]); CloseHandle(WinHandles[0]); CloseHandle(ReadEvent); return -1; } return 1; } // The pipe exported by the Handle2Fd class requires manual reset. void Handle2Fd::Reset() { ResetPipe(); } // Add a new handle to the class int Handle2Fd::AddHandle(HANDLE h) { // If the thread is running, we don't accept new handles. This reduces the syncronization requirements if (!WaitThreadHandle) { if (NHandles < sizeof(WinHandles) / sizeof(WinHandles[0]) - 1) { WinHandles[NHandles++] = h; return 1; } } return -1; } // Get the pipe file descriptor. int Handle2Fd::GetFd() { return PipeFds[0]; } // Kismet-like MergeSet function int Handle2Fd::MergeSet(fd_set *set, int max) { Reset(); // Manual reset if (!FD_ISSET(GetFd(), set)) { FD_SET(PipeFds[0], set); if (FirstFdSet) { max++; FirstFdSet = 0; } } return max; } // Nonzero if the HandleNumber event is set int Handle2Fd::IsEventSet(unsigned int HandleNumber) { if (WaitForSingleObject(WinHandles[HandleNumber + 1], 0) == WAIT_OBJECT_0) { return 1; } else { return 0; } } #endif kismet-2013-03-R1b/kis_panel_details.h0000664000175000017500000001647012124602454017306 0ustar dragorndragorn /* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_DETAILS_H__ #define __KIS_PANEL_DETAILS_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "globalregistry.h" #include "kis_clinetframe.h" #include "kis_panel_widgets.h" #include "kis_panel_network.h" #include "kis_panel_plugin.h" class KisPanelInterface; class Kis_NetDetails_Panel : public Kis_Panel { public: Kis_NetDetails_Panel() { fprintf(stderr, "FATAL OOPS: Kis_NetDetails_Panel called w/out globalreg\n"); exit(1); } Kis_NetDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_NetDetails_Panel(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); virtual int GraphTimer(); protected: int AppendNetworkInfo(vector *td, Kis_Display_NetGroup *tng, Netracker::tracked_network *net); int AppendSSIDInfo(vector *td, Netracker::tracked_network *net, Netracker::adv_ssid_data *ssid); virtual void UpdateViewMenu(int mi); void ClearGraphVectors(); void UpdateGraphVectors(int signal, int pps, int retry); int DeriveDisplayUpdate(); Kis_Panel_Packbox *vbox, *bbox; // Kis_Scrollable_Table *netdetails; Kis_Free_Text *netdetailt; Kis_IntGraph *siggraph, *packetgraph, *retrygraph; vector sigpoints, packetpps, retrypps; int lastpackets; time_t last_dirty; mac_addr last_mac; Kis_Display_NetGroup *dng; Kis_Button *closebutton, *prevbutton, *nextbutton; int mn_network, mi_addnote, mi_nextnet, mi_prevnet, mi_close; int mn_view, mi_net, mi_clients, mi_graphsig, mi_graphpacket, mi_graphretry; int grapheventid; }; #define KCLI_CHANDETAILS_CHANNEL_FIELDS "channel,time_on,packets,packetsdelta," \ "usecused,bytes,bytesdelta,networks,activenetworks,maxsignal_dbm,maxsignal_rssi," \ "maxnoise_dbm,maxnoise_rssi" #define KCLI_CHANDETAILS_CHANNEL_NUMFIELDS 13 class Kis_ChanDetails_Panel : public Kis_Panel { public: Kis_ChanDetails_Panel() { fprintf(stderr, "FATAL OOPS: Kis_ChanDetails_Panel called w/out globalreg\n"); exit(1); } Kis_ChanDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_ChanDetails_Panel(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); virtual int GraphTimer(); void NetClientConfigured(KisNetClient *in_cli, int in_recon); void NetClientAdd(KisNetClient *in_cli, int add); void Proto_CHANNEL(CLIPROTO_CB_PARMS); struct chan_sig_info { chan_sig_info() { last_updated = 0; channel = 0; channel_time_on = 0; packets = 0; packets_delta = 0; usec_used = 0; bytes_seen = 0; bytes_delta = 0; sig_dbm = 0; sig_rssi = 0; noise_dbm = 0; noise_rssi = 0; networks = 0; networks_active = 0; } time_t last_updated; int channel; int channel_time_on; int packets; int packets_delta; long int usec_used; long int bytes_seen; long int bytes_delta; int sig_dbm; int sig_rssi; int noise_dbm; int noise_rssi; int networks; int networks_active; }; protected: virtual void UpdateViewMenu(int mi); Kis_Panel_Packbox *vbox; Kis_Scrollable_Table *chansummary; Kis_IntGraph *siggraph, *packetgraph, *bytegraph, *netgraph; // Graph data pools vector sigvec, noisevec, packvec, bytevec, netvec, anetvec; vector graph_label_vec; // Channel records map channel_map; time_t last_dirty; int mn_channels, mi_lock, mi_hop, mi_close; int mn_view, mi_chansummary, mi_signal, mi_packets, mi_traffic, mi_networks; int grapheventid; int addref; }; class Kis_ClientDetails_Panel : public Kis_Panel { public: Kis_ClientDetails_Panel() { fprintf(stderr, "FATAL OOPS: Kis_ClientDetails_Panel called w/out globalreg\n"); exit(1); } Kis_ClientDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_ClientDetails_Panel(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); virtual int GraphTimer(); virtual void SetClientlist(Kis_Clientlist *in_list) { clientlist = in_list; } protected: virtual void UpdateViewMenu(int mi); void ClearGraphVectors(); void UpdateGraphVectors(int signal, int pps, int retry); int DeriveDisplayUpdate(); Kis_Panel_Packbox *vbox, *bbox; Kis_Free_Text *clientdetailt; Kis_IntGraph *siggraph, *packetgraph, *retrygraph; vector sigpoints, packetpps, retrypps; int lastpackets; time_t last_dirty; mac_addr last_mac; Kis_Display_NetGroup *dng; Netracker::tracked_client *dcli; int mn_client, mi_addnote, mi_nextcli, mi_prevcli, mi_close; int mn_view, mi_cli, mi_graphsig, mi_graphpacket, mi_graphretry; int grapheventid; Kis_Clientlist *clientlist; }; enum alertsort_opts { alertsort_time, alertsort_latest, alertsort_type, alertsort_bssid }; class Kis_AlertDetails_Panel : public Kis_Panel { public: Kis_AlertDetails_Panel() { fprintf(stderr, "FATAL OOPS: Kis_AlertDetails_Panel called w/out globalreg\n"); exit(1); } Kis_AlertDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_AlertDetails_Panel(); virtual void DrawPanel(); virtual void ButtonAction(Kis_Panel_Component *in_button); virtual void MenuAction(int opt); protected: virtual void UpdateSortMenu(int mi); virtual int UpdateSortPrefs(int always); Kis_Panel_Packbox *vbox; Kis_Scrollable_Table *alertlist, *alertdetails; time_t last_sort; alertsort_opts sort_mode; int mn_alert, mi_close; int mn_sort, mi_time, mi_latest, mi_type, mi_bssid; vector sorted_alerts; KisPanelInterface::knc_alert *last_alert, *last_selected; }; class Kis_RegDetails_Panel : public Kis_Panel { public: Kis_RegDetails_Panel() { fprintf(stderr, "FATAL OOPS: Kis_RegDetails_Panel called w/out globalreg\n"); exit(1); } Kis_RegDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_kpf); virtual ~Kis_RegDetails_Panel(); virtual void DrawPanel(); virtual void MenuAction(int opt); // Map country settings to a range of networks, one of these per // country + channel range we've seen. Divergent power ranges inside // an advertised country will show up as different regblocks struct reg_block { string dot11d_country; vector dot11d_vec; vector netgroup_vec; }; protected: Kis_Panel_Packbox *vbox; Kis_Scrollable_Table *reglist; Kis_Netlist *netlist, *main_netlist; Kis_Free_Text *text; int mn_regd, mi_close; vector regblock_vec; }; #endif #endif kismet-2013-03-R1b/text_cliframe.h0000664000175000017500000000264712124602454016463 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TEXTCLIFRAME_H__ #define __TEXTCLIFRAME_H__ #include "config.h" #include "clinetframework.h" #define TEXTCLI_PARMS string text, void *auxptr typedef void (*textcli_cb)(TEXTCLI_PARMS); class TextCliFrame : public ClientFramework { public: TextCliFrame() { fprintf(stderr, "FATAL OOPS: TextCliFrame()\n"); } TextCliFrame(GlobalRegistry *in_globalreg); virtual ~TextCliFrame(); int ParseData(); void RegisterNetworkClient(NetworkClient *in_netc); int RegisterCallback(textcli_cb in_cb, void *in_aux); void RemoveCallback(int in_id); struct textcli_cb_s { int id; textcli_cb cb; void *auxptr; }; protected: int next_id; vector callback_vec; }; #endif kismet-2013-03-R1b/madwifing_control.cc0000664000175000017500000001010612124602454017465 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef SYS_LINUX #include "madwifing_control.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifcontrol.h" int madwifing_list_vaps(const char *ifname, vector *retvec) { DIR *devdir; struct dirent *devfile; string dirpath; int kern24model = 0; FILE *pf = NULL; dirpath = "/sys/class/net/" + string(ifname) + "/device/"; if ((devdir = opendir(dirpath.c_str())) == NULL) { dirpath = "/proc/sys/net/"; if ((devdir = opendir(dirpath.c_str())) == NULL) { return -1; } kern24model = 1; } while ((devfile = readdir(devdir)) != NULL) { if (kern24model) { string pfname = dirpath + devfile->d_name + "/%parent"; char pname[64]; if ((pf = fopen(pfname.c_str(), "r")) == NULL) { continue; } else { if (fscanf(pf, "%s", pname) != 1) { fclose(pf); continue; } else { retvec->push_back(devfile->d_name); } fclose(pf); } } else { string ownername = "net:" + string(ifname); if (strncmp("net:", devfile->d_name, 4) == 0) retvec->push_back(devfile->d_name + 4); } } closedir(devdir); return retvec->size(); } int madwifing_find_parent(vector *vaplist) { for (unsigned int x = 0; x < vaplist->size(); x++) { if ((*vaplist)[x].find("wifi") != string::npos) return x; } return -1; } int madwifing_destroy_vap(const char *ifname, char *errstr) { struct ifreq ifr; int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, 1024, "Failed to create socket to madwifi: %s", strerror(errno)); return -1; } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sock, SIOC80211IFDESTROY, &ifr) < 0) { snprintf(errstr, 1024, "Failed to destroy VAP: %s", strerror(errno)); close(sock); return -1; } close(sock); return 1; } int madwifing_build_vap(const char *ifname, char *errstr, const char *vapname, char *retvapname, int vapmode, int vapflags) { struct ieee80211_clone_params { char icp_name[IFNAMSIZ]; uint16_t icp_opmode; uint16_t icp_flags; }; struct ieee80211_clone_params cp; struct ifreq ifr; int sock; char tnam[IFNAMSIZ]; // Find a numbered vapname which is useable for (unsigned int n = 0; n < 10; n++) { int fl; snprintf(tnam, IFNAMSIZ, "%s%d", vapname, n); if (Ifconfig_Get_Flags(tnam, errstr, &fl) < 0) break; // Default to no temp name as error tnam[0] = '\0'; } if (tnam[0] == '\0') { snprintf(errstr, 1024, "Unable to find free slot for VAP %s", vapname); return -1; } memset(&ifr, 0, sizeof(ifr)); memset(&cp, 0, sizeof(cp)); strncpy(cp.icp_name, tnam, IFNAMSIZ); cp.icp_opmode = vapmode; cp.icp_flags = vapflags; strncpy(ifr.ifr_name, ifname, IFNAMSIZ); ifr.ifr_data = (caddr_t) &cp; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, 1024, "Unable to create socket to madwifi-ng: %s", strerror(errno)); return -1; } if (ioctl(sock, SIOC80211IFCREATE, &ifr) < 0) { snprintf(errstr, 1024, "Unable to create VAP: %s", strerror(errno)); close(sock); return -1; } strncpy(retvapname, ifr.ifr_name, IFNAMSIZ); close(sock); return 1; } #endif kismet-2013-03-R1b/statealert.h0000664000175000017500000000347412124602454016004 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __STATEALERT_H__ #define __STATEALERT_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "alertracker.h" class StateAlert { public: StateAlert() { fprintf(stderr, "FATAL OOPS: StateAlert()\n"); exit(1); } StateAlert(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; } virtual ~StateAlert() { } virtual int ProcessPacket(kis_packet *in_pack) = 0; protected: GlobalRegistry *globalreg; }; class BSSTSStateAlert : public StateAlert { public: typedef struct { int incident; uint64_t bss_timestamp; struct timeval ts; } bss_rec; BSSTSStateAlert() { fprintf(stderr, "FATAL OOPS: BSSTimestampStateAlert()\n"); exit(1); } BSSTSStateAlert(GlobalRegistry *in_globalreg); virtual ~BSSTSStateAlert(); virtual int ProcessPacket(kis_packet *in_pack); protected: map state_map; int alert_bss_ts_ref; }; #endif kismet-2013-03-R1b/packetdissectors.cc0000664000175000017500000022215012124602454017336 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include "endian_magic.h" #include "packetdissectors.h" #include "packetsignatures.h" #include "packetchain.h" #include "alertracker.h" #include "configfile.h" #include "packetsource.h" #define PROTO_SSID_LEN 32 // Handly little global so that it only has to do the ascii->mac_addr transform once mac_addr broadcast_mac = "FF:FF:FF:FF:FF:FF"; const char *WEPKEY_fields_text[] = { "origin", "bssid", "key", "encrypted", "failed", NULL }; void proto_WEPKEY_enable(PROTO_ENABLE_PARMS) { ((KisBuiltinDissector *) data)->BlitKeys(in_fd); } int proto_WEPKEY(PROTO_PARMS) { wep_key_info *winfo = (wep_key_info *) data; ostringstream osstr; // We don't use the cache for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; osstr.str(""); switch (fnum) { case WEPKEY_origin: if (winfo->fragile == 0) out_string += "0"; else out_string += "1"; break; case WEPKEY_bssid: out_string += winfo->bssid.Mac2String(); break; case WEPKEY_key: /* printf("debug - key len %u\n", winfo->len); printf("debug - key %02hx%02hx%02hx%02hx\n", winfo->key[0], winfo->key[1], winfo->key[2], winfo->key[3]); */ for (unsigned int kpos = 0; kpos < WEPKEY_MAX && kpos < winfo->len; kpos++) { osstr << hex << setfill('0') << setw(2) << (int) winfo->key[kpos]; } out_string += osstr.str(); break; case WEPKEY_decrypted: out_string += IntToString(winfo->decrypted); break; case WEPKEY_failed: out_string += IntToString(winfo->failed); break; default: out_string = "\001Unknown field requested\001"; return -1; break; } out_string += " "; } return 1; } int clicmd_LISTWEPKEYS_hook(CLIENT_PARMS) { KisBuiltinDissector *di = (KisBuiltinDissector *) auxptr; return di->cmd_listwepkeys(in_clid, framework, globalreg, errstr, cmdline, parsedcmdline, auxptr); } int clicmd_ADDWEPKEY_hook(CLIENT_PARMS) { KisBuiltinDissector *di = (KisBuiltinDissector *) auxptr; return di->cmd_addwepkey(in_clid, framework, globalreg, errstr, cmdline, parsedcmdline, auxptr); } int clicmd_DELWEPKEY_hook(CLIENT_PARMS) { KisBuiltinDissector *di = (KisBuiltinDissector *) auxptr; return di->cmd_delwepkey(in_clid, framework, globalreg, errstr, cmdline, parsedcmdline, auxptr); } int clicmd_STRINGS_hook(CLIENT_PARMS) { KisBuiltinDissector *di = (KisBuiltinDissector *) auxptr; return di->cmd_strings(in_clid, framework, globalreg, errstr, cmdline, parsedcmdline, auxptr); } int clicmd_STRINGSFILTER_hook(CLIENT_PARMS) { KisBuiltinDissector *di = (KisBuiltinDissector *) auxptr; return di->cmd_stringsfilter(in_clid, framework, globalreg, errstr, cmdline, parsedcmdline, auxptr); } int pbd_blittimer(TIMEEVENT_PARMS) { ((KisBuiltinDissector *) parm)->BlitKeys(-1); return 1; } // CRC32 index for verifying WEP - cribbed from ethereal static const uint32_t wep_crc32_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; // Hooks into the real functions int kis_80211_dissector(CHAINCALL_PARMS) { KisBuiltinDissector *auxptr = (KisBuiltinDissector *) auxdata; return auxptr->ieee80211_dissector(in_pack); } int kis_data_dissector(CHAINCALL_PARMS) { KisBuiltinDissector *auxptr = (KisBuiltinDissector *) auxdata; return auxptr->basicdata_dissector(in_pack); } int kis_string_dissector(CHAINCALL_PARMS) { KisBuiltinDissector *auxptr = (KisBuiltinDissector *) auxdata; return auxptr->basicstring_dissector(in_pack); } int kis_wep_decryptor(CHAINCALL_PARMS) { KisBuiltinDissector *auxptr = (KisBuiltinDissector *) auxdata; return auxptr->wep_data_decryptor(in_pack); } const char *STRINGS_fields_text[] = { "bssid", "source", "dest", "string", NULL }; int proto_STRINGS(PROTO_PARMS) { string_proto_info *str = (string_proto_info *) data; // We don't use the cache for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; switch (fnum) { case STRINGS_string: out_string += string("\001") + (str->text) + string("\001"); break; case STRINGS_bssid: out_string += str->bssid.Mac2String(); break; case STRINGS_source: out_string += str->source.Mac2String(); break; case STRINGS_dest: out_string += str->dest.Mac2String(); break; default: out_string = "\001Unknown field requested\001"; return -1; break; } out_string += " "; } return 1; } KisBuiltinDissector::KisBuiltinDissector() { fprintf(stderr, "FATAL OOPS: KisBuiltinDissector called with no globalreg\n"); exit(1); } KisBuiltinDissector::KisBuiltinDissector(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; char errstr[STATUS_MAX]; string_filter = NULL; dissect_data = 1; dissect_strings = 0; dissect_all_strings = 0; if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: KisBuiltinDissector called before " "packetchain\n"); exit(1); } if (globalreg->alertracker == NULL) { fprintf(stderr, "FATAL OOPS: KisBuiltinDissector called before " "alertracker\n"); exit(1); } if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: KisBuiltinDissector called before " "kisnetserver\n"); exit(1); } // Register the basic stuff globalreg->packetchain->RegisterHandler(&kis_wep_decryptor, this, CHAINPOS_DECRYPT, -100); globalreg->packetchain->RegisterHandler(&kis_80211_dissector, this, CHAINPOS_LLCDISSECT, -100); globalreg->packetchain->RegisterHandler(&kis_data_dissector, this, CHAINPOS_DATADISSECT, -100); globalreg->packetchain->RegisterHandler(&kis_string_dissector, this, CHAINPOS_DATADISSECT, -99); _PCM(PACK_COMP_80211) = globalreg->packetchain->RegisterPacketComponent("IEEE80211_INFO"); _PCM(PACK_COMP_BASICDATA) = globalreg->packetchain->RegisterPacketComponent("BASICDATA_INFO"); _PCM(PACK_COMP_MANGLEFRAME) = globalreg->packetchain->RegisterPacketComponent("MANGLE_FRAME"); _PCM(PACK_COMP_STRINGS) = globalreg->packetchain->RegisterPacketComponent("STRINGS"); netstumbler_aref = globalreg->alertracker->ActivateConfiguredAlert("NETSTUMBLER"); nullproberesp_aref = globalreg->alertracker->ActivateConfiguredAlert("NULLPROBERESP"); lucenttest_aref = globalreg->alertracker->ActivateConfiguredAlert("LUCENTTEST"); msfbcomssid_aref = globalreg->alertracker->ActivateConfiguredAlert("MSFBCOMSSID"); msfdlinkrate_aref = globalreg->alertracker->ActivateConfiguredAlert("MSFDLINKRATE"); msfnetgearbeacon_aref = globalreg->alertracker->ActivateConfiguredAlert("MSFNETGEARBEACON"); longssid_aref = globalreg->alertracker->ActivateConfiguredAlert("LONGSSID"); disconcodeinvalid_aref = globalreg->alertracker->ActivateConfiguredAlert("DISCONCODEINVALID"); deauthcodeinvalid_aref = globalreg->alertracker->ActivateConfiguredAlert("DEAUTHCODEINVALID"); dhcp_clientid_aref = globalreg->alertracker->ActivateConfiguredAlert("DHCPCLIENTID"); // Register network protocols for WEP key transfer commands _NPM(PROTO_REF_WEPKEY) = globalreg->kisnetserver->RegisterProtocol("WEPKEY", 0, 0, WEPKEY_fields_text, &proto_WEPKEY, &proto_WEPKEY_enable, this); listwepkey_cmdid = globalreg->kisnetserver->RegisterClientCommand("LISTWEPKEYS", clicmd_LISTWEPKEYS_hook, this); addwepkey_cmdid = globalreg->kisnetserver->RegisterClientCommand("ADDWEPKEY", clicmd_ADDWEPKEY_hook, this); delwepkey_cmdid = globalreg->kisnetserver->RegisterClientCommand("DELWEPKEY", clicmd_DELWEPKEY_hook, this); _NPM(PROTO_REF_STRING) = globalreg->kisnetserver->RegisterProtocol("STRING", 0, 0, STRINGS_fields_text, &proto_STRINGS, NULL, this); strings_cmdid = globalreg->kisnetserver->RegisterClientCommand("STRINGS", clicmd_STRINGS_hook, this); stringsfilter_cmdid = globalreg->kisnetserver->RegisterClientCommand("ADDSTRINGSFILTER", clicmd_STRINGSFILTER_hook, this); blit_time_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &pbd_blittimer, this); // Do we process the whole data packet? // if (StrLower(globalreg->kismet_config->FetchOpt("hidedata")) == "true" || // StrLower(globalreg->kismet_config->FetchOpt("dontbeevil")) == "true") { if (globalreg->kismet_config->FetchOptBoolean("hidedata", 0) || globalreg->kismet_config->FetchOptBoolean("dontbeevil", 0)) { _MSG("hidedata= set in Kismet config. Kismet will ignore the contents " "of data packets entirely", MSGFLAG_INFO); dissect_data = 0; } // Convert the WEP mappings to our real map vector raw_wepmap_vec; raw_wepmap_vec = globalreg->kismet_config->FetchOptVec("wepkey"); for (size_t rwvi = 0; rwvi < raw_wepmap_vec.size(); rwvi++) { string wepline = raw_wepmap_vec[rwvi]; size_t rwsplit = wepline.find(","); if (rwsplit == string::npos) { _MSG("Malformed 'wepkey' option in the config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } mac_addr bssid_mac = wepline.substr(0, rwsplit).c_str(); if (bssid_mac.error == 1) { _MSG("Malformed 'wepkey' option in the config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } string rawkey = wepline.substr(rwsplit + 1, wepline.length() - (rwsplit + 1)); unsigned char key[WEPKEY_MAX]; int len = Hex2UChar((unsigned char *) rawkey.c_str(), key); if (len != 5 && len != 13 && len != 16) { snprintf(errstr, STATUS_MAX, "Invalid key '%s' length %d in a wepkey " "option in the config file.\n", rawkey.c_str(), len); _MSG(errstr, MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } wep_key_info *keyinfo = new wep_key_info; keyinfo->bssid = bssid_mac; keyinfo->fragile = 0; keyinfo->decrypted = 0; keyinfo->failed = 0; keyinfo->len = len; memcpy(keyinfo->key, key, sizeof(unsigned char) * WEPKEY_MAX); wepkeys.insert(bssid_mac, keyinfo); snprintf(errstr, STATUS_MAX, "Using key %s length %d for BSSID %s", rawkey.c_str(), len, bssid_mac.Mac2String().c_str()); _MSG(errstr, MSGFLAG_INFO); } // if (globalreg->kismet_config->FetchOpt("allowkeytransmit") == "true") { if (globalreg->kismet_config->FetchOptBoolean("allowkeytransmit", 0)) { _MSG("Allowing Kismet frontends to view WEP keys", MSGFLAG_INFO); client_wepkey_allowed = 1; } else { client_wepkey_allowed = 0; } // Build the wep identity for (unsigned int wi = 0; wi < 256; wi++) wep_identity[wi] = wi; string_filter = new FilterCore(globalreg); vector filterlines = globalreg->kismet_config->FetchOptVec("filter_string"); for (unsigned int fl = 0; fl < filterlines.size(); fl++) { if (string_filter->AddFilterLine(filterlines[fl]) < 0) { _MSG("Failed to add filter_string config line from the Kismet config " "file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } } } void KisBuiltinDissector::BlitKeys(int in_fd) { for (macmap::iterator x = wepkeys.begin(); x != wepkeys.end(); ++x) { kis_protocol_cache cache; if (in_fd == -1) { if (globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_WEPKEY), (void *) *(x->second)) < 0) break; } else { if (globalreg->kisnetserver->SendToClient(in_fd, _NPM(PROTO_REF_WEPKEY), (void *) *(x->second), &cache) < 0) break; } } } // Returns a pointer in the data block to the size byte of the desired tag, with the // tag offsets cached int KisBuiltinDissector::GetIEEETagOffsets(unsigned int init_offset, kis_datachunk *in_chunk, map > *tag_cache_map) { int cur_tag = 0; // Initial offset is 36, that's the first tag unsigned int cur_offset = (unsigned int) init_offset; uint8_t len; // Bail on invalid incoming offsets if (init_offset >= in_chunk->length) { return -1; } // If we haven't parsed the tags for this frame before, parse them all now. // Return an error code if one of them is malformed. if (tag_cache_map->size() == 0) { while (1) { // Are we over the packet length? if (cur_offset + 2 >= in_chunk->length) { break; } // Read the tag we're on and bail out if we're done cur_tag = (int) in_chunk->data[cur_offset]; // Move ahead one byte and read the length. len = (in_chunk->data[cur_offset+1] & 0xFF); // If this is longer than we have... if ((cur_offset + len + 2) > in_chunk->length) { return -1; } // (*tag_cache_map)[cur_tag] = cur_offset + 1; (*tag_cache_map)[cur_tag].push_back(cur_offset + 1); // Jump the length+length byte, this should put us at the next tag // number. cur_offset += len+2; } } return 0; } // Convert WPA cipher elements into crypt_set stuff int KisBuiltinDissector::WPACipherConv(uint8_t cipher_index) { int ret = crypt_wpa; switch (cipher_index) { case 1: ret |= crypt_wep40; break; case 2: ret |= crypt_tkip; break; case 3: ret |= crypt_aes_ocb; break; case 4: ret |= crypt_aes_ccm; break; case 5: ret |= crypt_wep104; break; default: ret = 0; break; } return ret; } // Convert WPA key management elements into crypt_set stuff int KisBuiltinDissector::WPAKeyMgtConv(uint8_t mgt_index) { int ret = crypt_wpa; switch (mgt_index) { case 1: ret |= crypt_wpa; break; case 2: ret |= crypt_psk; break; default: ret = 0; break; } return ret; } // This needs to be optimized and it needs to not use casting to do its magic int KisBuiltinDissector::ieee80211_dissector(kis_packet *in_pack) { static int debugpcknum = 0; if (in_pack->error) { return 0; } debugpcknum++; // printf("debug - packet %d\n", debugpcknum); // Extract data, bail if it doesn't exist, make a local copy of what we're // inserting into the frame. kis_ieee80211_packinfo *packinfo; kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME)); // If we can't grab an 802.11 chunk, grab the raw link frame if (chunk == NULL) { chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME)); if (chunk == NULL) { return 0; } } // If we don't have a dot11 frame, throw it away if (chunk->dlt != KDLT_IEEE802_11) return 0; kis_ref_capsource *capsrc = (kis_ref_capsource *) in_pack->fetch(_PCM(PACK_COMP_KISCAPSRC)); packet_parm srcparms; if (capsrc != NULL) srcparms = capsrc->ref_source->FetchGenericParms(); // Flat-out dump if it's not big enough to be 80211, don't even bother making a // packinfo record for it because we're completely broken if (chunk->length < 10) { return 0; } packinfo = new kis_ieee80211_packinfo; frame_control *fc = (frame_control *) chunk->data; // Inherit the FC privacy flag if (fc->wep) packinfo->cryptset |= crypt_wep; uint16_t duration = 0; // 18 bytes of normal address ranges uint8_t *addr0; uint8_t *addr1; uint8_t *addr2; // And an optional 6 bytes of address range for ds=0x03 packets uint8_t *addr3; // We'll fill these in as we go packinfo->type = packet_unknown; packinfo->subtype = packet_sub_unknown; packinfo->distrib = distrib_unknown; // Endian swap the duration ** Optimize this in the future ** memcpy(&duration, &(chunk->data[2]), 2); duration = kis_ntoh16(duration); // 2 bytes of sequence and fragment counts wireless_fragseq *sequence; // We always have addr0 even on phy addr0 = &(chunk->data[4]); if (fc->more_fragments) packinfo->fragmented = 1; if (fc->retry) packinfo->retry = 1; // Assign the distribution direction this packet is traveling if (fc->to_ds == 0 && fc->from_ds == 0) packinfo->distrib = distrib_adhoc; else if (fc->to_ds == 0 && fc->from_ds == 1) packinfo->distrib = distrib_from; else if (fc->to_ds == 1 && fc->from_ds == 0) packinfo->distrib = distrib_to; else if (fc->to_ds == 1 && fc->from_ds == 1) packinfo->distrib = distrib_inter; // Shortcut PHYs here because they're shorter than normal packets if (fc->type == packet_phy) { packinfo->type = packet_phy; // Throw away large phy packets just like we throw away large management. // Phy stuff is all really small, so we set the limit smaller. if (chunk->length > 128) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } if (fc->subtype == 10) { packinfo->subtype = packet_sub_pspoll; } else if (fc->subtype == 11) { packinfo->subtype = packet_sub_rts; } else if (fc->subtype == 12) { packinfo->subtype = packet_sub_cts; } else if (fc->subtype == 13) { packinfo->subtype = packet_sub_ack; packinfo->dest_mac = addr0; } else if (fc->subtype == 14) { packinfo->subtype = packet_sub_cf_end; } else if (fc->subtype == 15) { packinfo->subtype = packet_sub_cf_end_ack; } else { packinfo->subtype = packet_sub_unknown; } // Nothing more to do if we get a phy in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 1; } // Anything from this point on can't be less than 24 bytes since we need // a full 802.11 header, so throw it out // Flat-out dump if it's not big enough to be 80211. if (chunk->length < 24) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } addr1 = &(chunk->data[10]); addr2 = &(chunk->data[16]); sequence = (wireless_fragseq *) &(chunk->data[22]); addr3 = &(chunk->data[24]); packinfo->sequence_number = sequence->sequence; packinfo->frag_number = sequence->frag; unsigned int tag_offset = 0; unsigned int taglen = 0; // Rip apart management frames if (fc->type == packet_management) { packinfo->type = packet_management; packinfo->distrib = distrib_unknown; // Throw away large management frames that don't make any sense. 512b is // an arbitrary number to pick, but this should keep some drivers from messing // with us // TODO: Make this a driver option if (chunk->length > 512) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } fixed_parameters *fixparm = NULL; if (fc->subtype == 0) { packinfo->subtype = packet_sub_association_req; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; } else if (fc->subtype == 1) { packinfo->subtype = packet_sub_association_resp; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; } else if (fc->subtype == 2) { packinfo->subtype = packet_sub_reassociation_req; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; } else if (fc->subtype == 3) { packinfo->subtype = packet_sub_reassociation_resp; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; } else if (fc->subtype == 4) { packinfo->subtype = packet_sub_probe_req; packinfo->distrib = distrib_to; packinfo->source_mac = addr1; packinfo->bssid_mac = addr1; } else if (fc->subtype == 5) { packinfo->subtype = packet_sub_probe_resp; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; } else if (fc->subtype == 8) { packinfo->subtype = packet_sub_beacon; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; // If beacons aren't do a broadcast destination, consider them corrupt. if (packinfo->dest_mac != broadcast_mac) packinfo->corrupt = 1; } else if (fc->subtype == 9) { // I'm not positive this is the right handling of atim packets. // Do something smarter in the future packinfo->subtype = packet_sub_atim; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; packinfo->distrib = distrib_unknown; } else if (fc->subtype == 10) { packinfo->subtype = packet_sub_disassociation; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; uint16_t rcode; memcpy(&rcode, (const char *) &(chunk->data[24]), 2); packinfo->mgt_reason_code = rcode; } else if (fc->subtype == 11) { packinfo->subtype = packet_sub_authentication; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; uint16_t rcode; memcpy(&rcode, (const char *) &(chunk->data[24]), 2); packinfo->mgt_reason_code = rcode; } else if (fc->subtype == 12) { packinfo->subtype = packet_sub_deauthentication; packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; uint16_t rcode; memcpy(&rcode, (const char *) &(chunk->data[24]), 2); packinfo->mgt_reason_code = rcode; } else { packinfo->subtype = packet_sub_unknown; } if (fc->subtype == packet_sub_probe_req || fc->subtype == packet_sub_disassociation || fc->subtype == packet_sub_authentication || fc->subtype == packet_sub_deauthentication) { // Shortcut handling of probe req, disassoc, auth, deauth since they're // not normal management frames packinfo->header_offset = 24; fixparm = NULL; } else { // If we're not long enough to have the fixparm and look like a normal // mgt header, bail. if (chunk->length < 36) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } packinfo->header_offset = 36; fixparm = (fixed_parameters *) &(chunk->data[24]); if (fixparm->wep) { packinfo->cryptset |= crypt_wep; } // Set the transmitter info packinfo->ess = fixparm->ess; packinfo->ibss = fixparm->ibss; // Pull the fixparm ibss info if (fixparm->ess == 0 && fixparm->ibss == 1) { packinfo->distrib = distrib_adhoc; } // Pull the fixparm timestamp uint64_t temp_ts; memcpy(&temp_ts, fixparm->timestamp, 8); #ifdef WORDS_BIGENDIAN packinfo->timestamp = kis_swap64(temp_ts); #else packinfo->timestamp = temp_ts; #endif } // Look for MSF opcode beacons before tag decode if (fc->subtype == packet_sub_beacon && packinfo->source_mac == msfopcode_mac) { _ALERT(msfbcomssid_aref, in_pack, packinfo, "MSF-style poisoned beacon packet for Broadcom drivers detected"); } if (fc->subtype == packet_sub_beacon && chunk->length >= 1184) { if (memcmp(&(chunk->data[1180]), "\x6a\x39\x58\x01", 4) == 0) _ALERT(msfnetgearbeacon_aref, in_pack, packinfo, "MSF-style poisoned options in over-sized beacon for Netgear " "driver attack"); } map > tag_cache_map; map >::iterator tcitr; // Extract various tags from the packet int found_ssid_tag = 0; int found_rate_tag = 0; int found_channel_tag = 0; if (fc->subtype == packet_sub_beacon || fc->subtype == packet_sub_probe_req || fc->subtype == packet_sub_probe_resp) { if (fc->subtype == packet_sub_beacon) packinfo->beacon_interval = kis_letoh16(fixparm->beacon); // This is guaranteed to only give us tags that fit within the packets, // so we don't have to do more error checking if (GetIEEETagOffsets(packinfo->header_offset, chunk, &tag_cache_map) < 0) { if (srcparms.weak_dissect == 0) { // The frame is corrupt, bail packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } } if ((tcitr = tag_cache_map.find(0)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; found_ssid_tag = 1; taglen = (chunk->data[tag_offset] & 0xFF); packinfo->ssid_len = taglen; // Protect against malicious packets if (taglen == 0) { // do nothing for 0-length ssid's } else if (taglen <= PROTO_SSID_LEN) { // Test the SSID for cloaked len!=0 data==0 situation, // then munge it to something printable if it makes sense // to do so int zeroed = 1; for (unsigned int sp = 0; sp < taglen; sp++) { if (chunk->data[tag_offset+sp+1] != 0) { zeroed = 0; break; } } if (zeroed == 0) { packinfo->ssid = MungeToPrintable((char *) &(chunk->data[tag_offset+1]), taglen, 0); } else { packinfo->ssid_blank = 1; } } else { _ALERT(longssid_aref, in_pack, packinfo, "Illegal SSID (greater than 32 bytes) detected, this " "likely indicates an exploit attempt against a client"); // Otherwise we're corrupt, set it and stop processing packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } } else { packinfo->ssid_len = 0; } // Probe req's with no SSID are bad if (fc->subtype == packet_sub_probe_resp) { if (found_ssid_tag == 0) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } } // Extract the CISCO beacon info if ((tcitr = tag_cache_map.find(133)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; taglen = (chunk->data[tag_offset] & 0xFF); // Copy and munge the beacon info if it falls w/in our // boundaries if ((tag_offset + 11) < chunk->length && taglen >= 11) { packinfo->beacon_info = MungeToPrintable((char *) &(chunk->data[tag_offset+11]), taglen - 11, 1); } // Other conditions on beacon info non-fatal } // Extract the supported rates if ((tcitr = tag_cache_map.find(1)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; taglen = (chunk->data[tag_offset] & 0xFF); if (tag_offset + taglen > chunk->length) { // Otherwise we're corrupt, set it and stop processing packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } for (unsigned int t = 0; t < tcitr->second.size(); t++) { int moffset = tcitr->second[t]; if ((chunk->data[moffset] & 0xFF) == 75 && memcmp(&(chunk->data[moffset + 1]), "\xEB\x49", 2) == 0) { _ALERT(msfdlinkrate_aref, in_pack, packinfo, "MSF-style poisoned rate field in beacon for network " + packinfo->bssid_mac.Mac2String() + ", exploit attempt " "against D-Link drivers"); packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } } found_rate_tag = 1; for (unsigned int x = 0; x < taglen; x++) { if (packinfo->maxrate < (chunk->data[tag_offset+1+x] & 0x7F) * 0.5) packinfo->maxrate = (chunk->data[tag_offset+1+x] & 0x7F) * 0.5; } } // And the extended supported rates if ((tcitr = tag_cache_map.find(50)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; taglen = (chunk->data[tag_offset] & 0xFF); if (tag_offset + taglen > chunk->length) { // Otherwise we're corrupt, set it and stop processing packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } found_rate_tag = 1; for (unsigned int x = 0; x < taglen; x++) { if (packinfo->maxrate < (chunk->data[tag_offset+1+x] & 0x7F) * 0.5) packinfo->maxrate = (chunk->data[tag_offset+1+x] & 0x7F) * 0.5; } } // If beacons don't have a SSID and a basicrate then we consider them // corrupt if (found_ssid_tag == 0 || found_rate_tag == 0) { packinfo->corrupt = 1; } // Find the offset of flag 3 and get the channel. 802.11a doesn't have // this tag so we use the hardware channel, assigned at the beginning of // GetPacketInfo if ((tcitr = tag_cache_map.find(3)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; found_channel_tag = 1; // Extract the channel from the next byte (GetTagOffset returns // us on the size byte) taglen = (chunk->data[tag_offset] & 0xFF); if (tag_offset + taglen > chunk->length) { // Otherwise we're corrupt, set it and stop processing packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } packinfo->channel = (int) (chunk->data[tag_offset+1]); } if ((tcitr = tag_cache_map.find(7)) != tag_cache_map.end()) { tag_offset = tcitr->second[0]; taglen = (chunk->data[tag_offset] & 0xFF); tag_offset++; if (tag_offset + taglen > chunk->length) { // country tags only valid if 6 bytes or more, ubnt throws // broken ones on some APs if (taglen > 6) { packinfo->dot11d_country = MungeToPrintable(string((const char *) &(chunk->data[tag_offset]), 0, 3)); // We don't have to check taglen since we check that above for (unsigned int p = 3; p + 3 <= taglen; p += 3) { dot11d_range_info ri; ri.startchan = chunk->data[tag_offset + p]; ri.numchan = chunk->data[tag_offset + p + 1]; ri.txpower = chunk->data[tag_offset + p + 2]; packinfo->dot11d_vec.push_back(ri); } } } } // WPA frame matching if we have the privacy bit set if ((packinfo->cryptset & crypt_wep)) { // Liberally borrowed from Ethereal if ((tcitr = tag_cache_map.find(221)) != tag_cache_map.end()) { for (unsigned int tagct = 0; tagct < tcitr->second.size(); tagct++) { tag_offset = tcitr->second[tagct]; unsigned int tag_orig = tag_offset + 1; unsigned int taglen = (chunk->data[tag_offset] & 0xFF); unsigned int offt = 0; if (tag_orig + taglen > chunk->length) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } // Match 221 tag header for WPA if (taglen < 6) continue; if (memcmp(&(chunk->data[tag_orig + offt]), WPA_OUI, sizeof(WPA_OUI))) continue; offt += 6; // Match WPA multicast suite if (offt + 4 > taglen) continue; if (memcmp(&(chunk->data[tag_orig + offt]), WPA_OUI, sizeof(WPA_OUI))) continue; packinfo->cryptset |= WPACipherConv(chunk->data[tag_orig + offt + 3]); // We don't care about parsing the number of ciphers, // we'll just iterate, so skip the cipher number offt += 6; // Match WPA unicast components while (offt + 4 <= taglen) { if (memcmp(&(chunk->data[tag_orig + offt]), WPA_OUI, sizeof(WPA_OUI)) == 0) { packinfo->cryptset |= WPACipherConv(chunk->data[tag_orig + offt + 3]); offt += 4; } else { break; } } // WPA Migration Mode if ((packinfo->cryptset & crypt_tkip) && ((packinfo->cryptset & crypt_wep40) || (packinfo->cryptset & crypt_wep104)) ) packinfo->cryptset |= crypt_wpa_migmode; // Match auth key components offt += 2; while (offt + 4 <= taglen) { if (memcmp(&(chunk->data[tag_orig + offt]), WPA_OUI, sizeof(WPA_OUI)) == 0) { packinfo->cryptset |= WPAKeyMgtConv(chunk->data[tag_orig + offt + 3]); offt += 4; } else { break; } } } } /* 221 */ // Match tag 48 RSN WPA2 if ((tcitr = tag_cache_map.find(48)) != tag_cache_map.end()) { for (unsigned int tagct = 0; tagct < tcitr->second.size(); tagct++) { tag_offset = tcitr->second[tagct]; unsigned int tag_orig = tag_offset + 1; unsigned int taglen = (chunk->data[tag_offset] & 0xFF); unsigned int offt = 0; if (tag_orig + taglen > chunk->length || taglen < 6) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } // Skip version offt += 2; // Match multicast if (offt + 3 > taglen || memcmp(&(chunk->data[tag_orig + offt]), RSN_OUI, sizeof(RSN_OUI))) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } packinfo->cryptset |= WPACipherConv(chunk->data[tag_orig + offt + 3]); offt += 4; // We don't care about unicast number offt += 2; while (offt + 4 <= taglen) { if (memcmp(&(chunk->data[tag_orig + offt]), RSN_OUI, sizeof(RSN_OUI)) == 0) { packinfo->cryptset |= WPACipherConv(chunk->data[tag_orig + offt + 3]); offt += 4; } else { break; } } // We don't care about authkey number offt += 2; while (offt + 4 <= taglen) { if (memcmp(&(chunk->data[tag_orig + offt]), RSN_OUI, sizeof(RSN_OUI)) == 0) { packinfo->cryptset |= WPAKeyMgtConv(chunk->data[tag_orig + offt + 3]); offt += 4; } else { break; } } } } /* 48 */ } } else if (fc->subtype == packet_sub_deauthentication) { if ((packinfo->mgt_reason_code >= 25 && packinfo->mgt_reason_code <= 31) || packinfo->mgt_reason_code > 45) { _ALERT(deauthcodeinvalid_aref, in_pack, packinfo, "Unknown deauthentication code " + HexIntToString(packinfo->mgt_reason_code) + " from network " + packinfo->bssid_mac.Mac2String()); } } else if (fc->subtype == packet_sub_disassociation) { if ((packinfo->mgt_reason_code >= 25 && packinfo->mgt_reason_code <= 31) || packinfo->mgt_reason_code > 45) { _ALERT(disconcodeinvalid_aref, in_pack, packinfo, "Unknown disassociation code " + HexIntToString(packinfo->mgt_reason_code) + " from network " + packinfo->bssid_mac.Mac2String()); } } } else if (fc->type == 2) { packinfo->type = packet_data; // Collect the subtypes - we probably want to do something better with thse // in the future if (fc->subtype == 0) { packinfo->subtype = packet_sub_data; } else if (fc->subtype == 1) { packinfo->subtype = packet_sub_data_cf_ack; } else if (fc->subtype == 2) { packinfo->subtype = packet_sub_data_cf_poll; } else if (fc->subtype == 3) { packinfo->subtype = packet_sub_data_cf_ack_poll; } else if (fc->subtype == 4) { packinfo->subtype = packet_sub_data_null; } else if (fc->subtype == 5) { packinfo->subtype = packet_sub_cf_ack; } else if (fc->subtype == 6) { packinfo->subtype = packet_sub_cf_ack_poll; } else if (fc->subtype == 8) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_data; packinfo->header_offset += 2; } else if (fc->subtype == 9) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_data_cf_ack; packinfo->header_offset += 2; } else if (fc->subtype == 10) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_data_cf_poll; packinfo->header_offset += 2; } else if (fc->subtype == 11) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_data_cf_ack_poll; packinfo->header_offset += 2; } else if (fc->subtype == 12) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_null; packinfo->header_offset += 2; } else if (fc->subtype == 14) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_cf_poll_nod; packinfo->header_offset += 2; } else if (fc->subtype == 15) { // Ugly hack, do this better packinfo->subtype = packet_sub_data_qos_cf_ack_poll; packinfo->header_offset += 2; } else { packinfo->corrupt = 1; packinfo->subtype = packet_sub_unknown; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } int datasize = chunk->length - packinfo->header_offset; if (datasize > 0) packinfo->datasize = datasize; // Extract ID's switch (packinfo->distrib) { case distrib_adhoc: packinfo->dest_mac = addr0; packinfo->source_mac = addr1; packinfo->bssid_mac = addr2; if (packinfo->bssid_mac.longmac == 0) packinfo->bssid_mac = packinfo->source_mac; packinfo->header_offset += 24; break; case distrib_from: packinfo->dest_mac = addr0; packinfo->bssid_mac = addr1; packinfo->source_mac = addr2; packinfo->header_offset += 24; break; case distrib_to: packinfo->bssid_mac = addr0; packinfo->source_mac = addr1; packinfo->dest_mac = addr2; packinfo->header_offset += 24; break; case distrib_unknown: // If we aren't long enough to hold a intra-ds packet, bail if (chunk->length < 30) { packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; } packinfo->bssid_mac = addr1; packinfo->source_mac = addr3; packinfo->dest_mac = addr0; packinfo->distrib = distrib_inter; // First byte of offsets packinfo->header_offset += 30; break; default: packinfo->corrupt = 1; in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 0; break; } } // Do a little sanity checking on the BSSID if (packinfo->bssid_mac.error == 1 || packinfo->source_mac.error == 1 || packinfo->dest_mac.error == 1) { packinfo->corrupt = 1; } in_pack->insert(_PCM(PACK_COMP_80211), packinfo); return 1; } int KisBuiltinDissector::basicdata_dissector(kis_packet *in_pack) { kis_data_packinfo *datainfo = NULL; if (in_pack->error) return 0; // Grab the 80211 info, compare, bail kis_ieee80211_packinfo *packinfo; if ((packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211))) == NULL) return 0; if (packinfo->corrupt) return 0; if (packinfo->type != packet_data || (packinfo->subtype != packet_sub_data && packinfo->subtype != packet_sub_data_qos_data)) return 0; // Grab the mangled frame if we have it, then try to grab up the list of // data types and die if we can't get anything kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } } // If we don't have a dot11 frame, throw it away if (chunk->dlt != KDLT_IEEE802_11) { // printf("debug - dissector wrong dlt\n"); return 0; } // Blow up on no content if (packinfo->header_offset > chunk->length) { // printf("debug - offset > len\n"); return 0; } // If we're not processing data, short circuit the whole packet if (dissect_data == 0) { chunk->length = packinfo->header_offset; return 0; } unsigned int header_offset = packinfo->header_offset; // If it's wep, get the IVs if (chunk->length > header_offset + 3 && packinfo->cryptset == crypt_wep) { datainfo = new kis_data_packinfo; memcpy(datainfo->ivset, &(chunk->data[header_offset]), 3); in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } // We can't do anything else if it's encrypted if (packinfo->cryptset != 0 && packinfo->decrypted == 0) { // printf("debug - packetdissector crypted packet\n"); return 0; } datainfo = new kis_data_packinfo; if (chunk->length > header_offset + LLC_UI_OFFSET + sizeof(PROBE_LLC_SIGNATURE) && memcmp(&(chunk->data[header_offset]), LLC_UI_SIGNATURE, sizeof(LLC_UI_SIGNATURE)) == 0) { // Handle the batch of frames that fall under the LLC UI 0x3 frame if (memcmp(&(chunk->data[header_offset + LLC_UI_OFFSET]), PROBE_LLC_SIGNATURE, sizeof(PROBE_LLC_SIGNATURE)) == 0) { // Packets that look like netstumber probes... if (header_offset + NETSTUMBLER_OFFSET + sizeof(NETSTUMBLER_322_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + NETSTUMBLER_OFFSET]), NETSTUMBLER_322_SIGNATURE, sizeof(NETSTUMBLER_322_SIGNATURE)) == 0) { _ALERT(netstumbler_aref, in_pack, packinfo, "Detected Netstumbler 3.22 probe"); datainfo->proto = proto_netstumbler_probe; datainfo->field1 = 322; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } if (header_offset + NETSTUMBLER_OFFSET + sizeof(NETSTUMBLER_323_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + NETSTUMBLER_OFFSET]), NETSTUMBLER_323_SIGNATURE, sizeof(NETSTUMBLER_323_SIGNATURE)) == 0) { _ALERT(netstumbler_aref, in_pack, packinfo, "Detected Netstumbler 3.23 probe"); datainfo->proto = proto_netstumbler_probe; datainfo->field1 = 323; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } if (header_offset + NETSTUMBLER_OFFSET + sizeof(NETSTUMBLER_330_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + NETSTUMBLER_OFFSET]), NETSTUMBLER_330_SIGNATURE, sizeof(NETSTUMBLER_330_SIGNATURE)) == 0) { _ALERT(netstumbler_aref, in_pack, packinfo, "Detected Netstumbler 3.30 probe"); datainfo->proto = proto_netstumbler_probe; datainfo->field1 = 330; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } if (header_offset + LUCENT_OFFSET + sizeof(LUCENT_TEST_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + LUCENT_OFFSET]), LUCENT_TEST_SIGNATURE, sizeof(LUCENT_TEST_SIGNATURE)) == 0) { _ALERT(lucenttest_aref, in_pack, packinfo, "Detected Lucent probe/link test"); datainfo->proto = proto_lucent_probe; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } _ALERT(netstumbler_aref, in_pack, packinfo, "Detected what looks like a Netstumber probe but didn't " "match known version fingerprint"); datainfo->proto = proto_netstumbler_probe; datainfo->field1 = -1; } // LLC_SIGNATURE // We don't bail right here, if anything looks "more" like something // else then we'll let it take over } // LLC_UI // Fortress LLC if ((header_offset + LLC_UI_OFFSET + 1 + sizeof(FORTRESS_SIGNATURE)) < chunk->length && memcmp(&(chunk->data[header_offset + LLC_UI_OFFSET]), FORTRESS_SIGNATURE, sizeof(FORTRESS_SIGNATURE)) == 0) { packinfo->cryptset |= crypt_fortress; } // CDP cisco discovery frames, good for finding unauthorized APs // +1 for the version frame we compare first if ((header_offset + LLC_UI_OFFSET + 1 + sizeof(CISCO_SIGNATURE)) < chunk->length && memcmp(&(chunk->data[header_offset + LLC_UI_OFFSET]), CISCO_SIGNATURE, sizeof(CISCO_SIGNATURE)) == 0) { unsigned int offset = 0; // Look for frames the old way, maybe v1 used it? Compare the versions. // I don't remember why the code worked this way. if (chunk->data[header_offset + LLC_UI_OFFSET + sizeof(CISCO_SIGNATURE)] == 2) offset = header_offset + LLC_UI_OFFSET + sizeof(CISCO_SIGNATURE) + 4; else offset = header_offset + LLC_UI_OFFSET + 12; // Did we get useful info? int gotinfo = 0; while (offset + CDP_ELEMENT_LEN < chunk->length) { // uint16_t dot1x_length = kis_extract16(&(chunk->data[offset + 2])); uint16_t elemtype = kis_ntoh16(kis_extract16(&(chunk->data[offset + 0]))); uint16_t elemlen = kis_ntoh16(kis_extract16(&(chunk->data[offset + 2]))); if (elemlen == 0) break; if (offset + elemlen >= chunk->length) break; if (elemtype == 0x01) { // Device id, we care about this if (elemlen < 4) { _MSG("Corrupt CDP frame (possibly an exploit attempt), discarded", MSGFLAG_ERROR); packinfo->corrupt = 1; delete(datainfo); return 0; } datainfo->cdp_dev_id = MungeToPrintable((char *) &(chunk->data[offset + 4]), elemlen - 4, 0); gotinfo = 1; } else if (elemtype == 0x03) { if (elemlen < 4) { _MSG("Corrupt CDP frame (possibly an exploit attempt), discarded", MSGFLAG_ERROR); packinfo->corrupt = 1; delete(datainfo); return 0; } datainfo->cdp_port_id = MungeToPrintable((char *) &(chunk->data[offset + 4]), elemlen - 4, 0); gotinfo = 1; } offset += elemlen; } if (gotinfo) { datainfo->proto = proto_cdp; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } } // Dot1x frames // +1 for the version byte at header_offset + hot1x off // +3 for the offset past LLC_UI if ((header_offset + LLC_UI_OFFSET + 4 + sizeof(DOT1X_PROTO)) < chunk->length && memcmp(&(chunk->data[header_offset + LLC_UI_OFFSET + 3]), DOT1X_PROTO, sizeof(DOT1X_PROTO)) == 0) { // It's dot1x, is it LEAP? // // Make sure its an EAP socket unsigned int offset = header_offset + DOT1X_OFFSET; // Dot1x bits uint8_t dot1x_version = chunk->data[offset]; uint8_t dot1x_type = chunk->data[offset + 1]; // uint16_t dot1x_length = kis_extract16(&(chunk->data[offset + 2])); offset += EAP_OFFSET; if (dot1x_version != 1 || dot1x_type != 0 || offset + EAP_PACKET_SIZE >= chunk->length) { delete datainfo; return 0; } // Eap bits uint8_t eap_code = chunk->data[offset]; // uint8_t eap_id = chunk->data[offset + 1]; // uint16_t eap_length = kis_extract16(&(chunk->data[offset + 2])); uint8_t eap_type = chunk->data[offset + 4]; switch (eap_type) { case EAP_TYPE_LEAP: datainfo->proto = proto_leap; datainfo->field1 = eap_code; packinfo->cryptset |= crypt_leap; break; case EAP_TYPE_TLS: datainfo->proto = proto_tls; datainfo->field1 = eap_code; packinfo->cryptset |= crypt_tls; break; case EAP_TYPE_TTLS: datainfo->proto = proto_ttls; datainfo->field1 = eap_code; packinfo->cryptset |= crypt_ttls; break; case EAP_TYPE_PEAP: datainfo->proto = proto_peap; datainfo->field1 = eap_code; packinfo->cryptset |= crypt_peap; break; default: datainfo->proto = proto_eap_unknown; break; } in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } if (header_offset + kismax(20, ARP_OFFSET + ARP_PACKET_SIZE) < chunk->length && header_offset + ARP_OFFSET + sizeof(ARP_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + ARP_OFFSET]), ARP_SIGNATURE, sizeof(ARP_SIGNATURE)) == 0) { // If we look like a ARP frame and we're big enough to be an arp // frame... datainfo->proto = proto_arp; memcpy(&(datainfo->ip_source_addr.s_addr), &(chunk->data[header_offset + ARP_OFFSET + 16]), 4); in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } if (header_offset + kismax(UDP_OFFSET + 4, IP_OFFSET + 11) < chunk->length && header_offset + IP_OFFSET + sizeof(TCP_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + IP_OFFSET]), UDP_SIGNATURE, sizeof(UDP_SIGNATURE)) == 0) { // UDP frame... datainfo->ip_source_port = kis_ntoh16(kis_extract16(&(chunk->data[header_offset + UDP_OFFSET]))); datainfo->ip_dest_port = kis_ntoh16(kis_extract16(&(chunk->data[header_offset + UDP_OFFSET + 2]))); memcpy(&(datainfo->ip_source_addr.s_addr), &(chunk->data[header_offset + IP_OFFSET + 3]), 4); memcpy(&(datainfo->ip_dest_addr.s_addr), &(chunk->data[header_offset + IP_OFFSET + 7]), 4); if (datainfo->ip_source_port == IAPP_PORT && datainfo->ip_dest_port == IAPP_PORT && (header_offset + IAPP_OFFSET + IAPP_HEADER_SIZE) < chunk->length) { uint8_t iapp_version = chunk->data[header_offset + IAPP_OFFSET]; uint8_t iapp_type = chunk->data[header_offset + IAPP_OFFSET + 1]; // If we can't understand the iapp version, bail and return the // UDP frame we DID decode if (iapp_version != 1) { in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } // Same again -- bail on UDP if we can't make sense of this switch (iapp_type) { case iapp_announce_request: case iapp_announce_response: case iapp_handover_request: case iapp_handover_response: break; default: in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; break; } unsigned int pdu_offset = header_offset + IAPP_OFFSET + IAPP_HEADER_SIZE; while (pdu_offset + IAPP_PDUHEADER_SIZE < chunk->length) { uint8_t *pdu = &(chunk->data[pdu_offset]); uint8_t pdu_type = pdu[0]; uint8_t pdu_len = pdu[1]; // If we have a short/malformed PDU frame, bail if ((pdu_offset + 3 + pdu_len) >= chunk->length) { delete datainfo; return 0; } switch (pdu_type) { case iapp_pdu_ssid: if (pdu_len > SSID_SIZE) break; packinfo->ssid = MungeToPrintable((char *) &(pdu[3]), pdu_len, 0); break; case iapp_pdu_bssid: if (pdu_len != MAC_LEN) break; packinfo->bssid_mac = mac_addr(&(pdu[3])); break; case iapp_pdu_capability: if (pdu_len != 1) break; if ((pdu[3] & iapp_cap_wep)) packinfo->cryptset |= crypt_wep; break; case iapp_pdu_channel: if (pdu_len != 1) break; packinfo->channel = (int) pdu[3]; break; case iapp_pdu_beaconint: if (pdu_len != 2) break; packinfo->beacon_interval = (int) ((pdu[3] << 8) | pdu[4]); break; case iapp_pdu_oldbssid: case iapp_pdu_msaddr: case iapp_pdu_announceint: case iapp_pdu_hotimeout: case iapp_pdu_messageid: case iapp_pdu_phytype: case iapp_pdu_regdomain: case iapp_pdu_ouiident: case iapp_pdu_authinfo: default: break; } pdu_offset += pdu_len + 3; } datainfo->proto = proto_iapp; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } // IAPP port if ((datainfo->ip_source_port == ISAKMP_PORT || datainfo->ip_dest_port == ISAKMP_PORT) && (header_offset + ISAKMP_OFFSET + ISAKMP_PACKET_SIZE) < chunk->length) { datainfo->proto = proto_isakmp; datainfo->field1 = chunk->data[header_offset + ISAKMP_OFFSET + 4]; packinfo->cryptset |= crypt_isakmp; in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } /* DHCP Offer */ if (packinfo->dest_mac == broadcast_mac && datainfo->ip_source_port == 67 && datainfo->ip_dest_port == 68) { // Extract the DHCP tags the same way we get IEEE 80211 tags, // infact we can re-use the code map > dhcp_tag_map; // This is convenient since it won't return anything that is outside // the context of the packet, we can feed it the length w/out checking // and we can trust the tags GetIEEETagOffsets(header_offset + DHCPD_OFFSET + 252, chunk, &dhcp_tag_map); if (dhcp_tag_map.find(53) != dhcp_tag_map.end() && dhcp_tag_map[53].size() != 0 && chunk->data[dhcp_tag_map[53][0] + 1] == 0x02) { // We're a DHCP offer... datainfo->proto = proto_dhcp_offer; // This should never be possible, but let's check if ((header_offset + DHCPD_OFFSET + 32) >= chunk->length) { delete datainfo; return 0; } memcpy(&(datainfo->ip_dest_addr.s_addr), &(chunk->data[header_offset + DHCPD_OFFSET + 28]), 4); if (dhcp_tag_map.find(1) != dhcp_tag_map.end() && dhcp_tag_map[1].size() != 0) { memcpy(&(datainfo->ip_netmask_addr.s_addr), &(chunk->data[dhcp_tag_map[1][0] + 1]), 4); } if (dhcp_tag_map.find(3) != dhcp_tag_map.end() && dhcp_tag_map[3].size() != 0) { memcpy(&(datainfo->ip_gateway_addr.s_addr), &(chunk->data[dhcp_tag_map[3][0] + 1]), 4); } } } /* DHCP Discover */ if (packinfo->dest_mac == broadcast_mac && datainfo->ip_source_port == 68 && datainfo->ip_dest_port == 67) { // Extract the DHCP tags the same way we get IEEE 80211 tags, // infact we can re-use the code map > dhcp_tag_map; // This is convenient since it won't return anything that is outside // the context of the packet, we can feed it the length w/out checking // and we can trust the tags GetIEEETagOffsets(header_offset + DHCPD_OFFSET + 252, chunk, &dhcp_tag_map); if (dhcp_tag_map.find(53) != dhcp_tag_map.end() && dhcp_tag_map[53].size() != 0 && chunk->data[dhcp_tag_map[53][0] + 1] == 0x01) { // We're definitely a dhcp discover datainfo->proto = proto_dhcp_discover; if (dhcp_tag_map.find(12) != dhcp_tag_map.end() && dhcp_tag_map[12].size() != 0) { datainfo->discover_host = string((char *) &(chunk->data[dhcp_tag_map[12][0] + 1]), chunk->data[dhcp_tag_map[12][0]]); datainfo->discover_host = MungeToPrintable(datainfo->discover_host); } if (dhcp_tag_map.find(60) != dhcp_tag_map.end() && dhcp_tag_map[60].size() != 0) { datainfo->discover_vendor = string((char *) &(chunk->data[dhcp_tag_map[60][0] + 1]), chunk->data[dhcp_tag_map[60][0]]); datainfo->discover_vendor = MungeToPrintable(datainfo->discover_vendor); } if (dhcp_tag_map.find(61) != dhcp_tag_map.end() && dhcp_tag_map[61].size() == 7) { mac_addr clmac = mac_addr(&(chunk->data[dhcp_tag_map[61][0] + 2])); if (clmac != packinfo->source_mac) { _ALERT(dhcp_clientid_aref, in_pack, packinfo, string("DHCP request on network ") + packinfo->bssid_mac.Mac2String() + string(" from ") + packinfo->source_mac.Mac2String() + string(" doesn't match DHCP DISCOVER client id ") + clmac.Mac2String() + string(" which can indicate " "a DHCP spoofing attack")); } } } } in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } // UDP frame if (header_offset + kismax(TCP_OFFSET + 4, IP_OFFSET + TCP_HEADER_SIZE) < chunk->length && header_offset + IP_OFFSET + sizeof(TCP_SIGNATURE) < chunk->length && memcmp(&(chunk->data[header_offset + IP_OFFSET]), TCP_SIGNATURE, sizeof(TCP_SIGNATURE)) == 0) { // TCP frame... datainfo->ip_source_port = kis_ntoh16(kis_extract16(&(chunk->data[header_offset + TCP_OFFSET]))); datainfo->ip_dest_port = kis_ntoh16(kis_extract16(&(chunk->data[header_offset + TCP_OFFSET + 2]))); memcpy(&(datainfo->ip_source_addr.s_addr), &(chunk->data[header_offset + IP_OFFSET + 3]), 4); memcpy(&(datainfo->ip_dest_addr.s_addr), &(chunk->data[header_offset + IP_OFFSET + 7]), 4); datainfo->proto = proto_tcp; if (datainfo->ip_source_port == PPTP_PORT || datainfo->ip_dest_port == PPTP_PORT) { datainfo->proto = proto_pptp; packinfo->cryptset |= crypt_pptp; } in_pack->insert(_PCM(PACK_COMP_BASICDATA), datainfo); return 1; } // TCP frame // Trash the data if we didn't fill it in delete(datainfo); return 1; } kis_datachunk *KisBuiltinDissector::DecryptWEP(kis_ieee80211_packinfo *in_packinfo, kis_datachunk *in_chunk, unsigned char *in_key, int in_key_len, unsigned char *in_id) { kis_datachunk *manglechunk = NULL; if (in_packinfo->corrupt) return NULL; // If we don't have a dot11 frame, throw it away if (in_chunk->dlt != KDLT_IEEE802_11) return NULL; // Bail on size check if (in_chunk->length < in_packinfo->header_offset || in_chunk->length - in_packinfo->header_offset <= 8) return NULL; // Password field char pwd[WEPKEY_MAX + 3]; memset(pwd, 0, WEPKEY_MAX + 3); // Extract the IV and add it to the key pwd[0] = in_chunk->data[in_packinfo->header_offset + 0] & 0xFF; pwd[1] = in_chunk->data[in_packinfo->header_offset + 1] & 0xFF; pwd[2] = in_chunk->data[in_packinfo->header_offset + 2] & 0xFF; // Add the supplied password to the key memcpy(pwd + 3, in_key, WEPKEY_MAX); int pwdlen = 3 + in_key_len; // Prepare the keyblock for the rc4 cipher unsigned char keyblock[256]; memcpy(keyblock, in_id, 256); int kba = 0, kbb = 0; for (kba = 0; kba < 256; kba++) { kbb = (kbb + keyblock[kba] + pwd[kba % pwdlen]) & 0xFF; unsigned char oldkey = keyblock[kba]; keyblock[kba] = keyblock[kbb]; keyblock[kbb] = oldkey; } // Allocate the mangled chunk -- 4 byte IV/Key# gone, 4 byte ICV gone manglechunk = new kis_datachunk; manglechunk->dlt = in_chunk->dlt; manglechunk->length = in_chunk->length - 8; manglechunk->data = new uint8_t[manglechunk->length]; // Copy the packet headers to the new chunk memcpy(manglechunk->data, in_chunk->data, in_packinfo->header_offset); // Decrypt the data payload and check the CRC kba = kbb = 0; uint32_t crc = ~0; uint8_t c_crc[4]; uint8_t icv[4]; // Copy the ICV into the CRC buffer for checking memcpy(icv, &(in_chunk->data[in_chunk->length - 4]), 4); for (unsigned int dpos = in_packinfo->header_offset + 4; dpos < in_chunk->length - 4; dpos++) { kba = (kba + 1) & 0xFF; kbb = (kbb + keyblock[kba]) & 0xFF; unsigned char oldkey = keyblock[kba]; keyblock[kba] = keyblock[kbb]; keyblock[kbb] = oldkey; // Decode the packet into the mangle chunk manglechunk->data[dpos - 4] = in_chunk->data[dpos] ^ keyblock[(keyblock[kba] + keyblock[kbb]) & 0xFF]; crc = wep_crc32_table[(crc ^ manglechunk->data[dpos - 4]) & 0xFF] ^ (crc >> 8); } // Check the CRC crc = ~crc; c_crc[0] = crc; c_crc[1] = crc >> 8; c_crc[2] = crc >> 16; c_crc[3] = crc >> 24; int crcfailure = 0; for (unsigned int crcpos = 0; crcpos < 4; crcpos++) { kba = (kba + 1) & 0xFF; kbb = (kbb + keyblock[kba]) & 0xFF; unsigned char oldkey = keyblock[kba]; keyblock[kba] = keyblock[kbb]; keyblock[kbb] = oldkey; if ((c_crc[crcpos] ^ keyblock[(keyblock[kba] + keyblock[kbb]) & 0xFF]) != icv[crcpos]) { crcfailure = 1; break; } } // If the CRC check failed, delete the moddata if (crcfailure) { delete manglechunk; return NULL; } // Remove the privacy flag in the mangled data frame_control *fc = (frame_control *) manglechunk->data; fc->wep = 0; return manglechunk; } int KisBuiltinDissector::wep_data_decryptor(kis_packet *in_pack) { kis_datachunk *manglechunk = NULL; if (in_pack->error) return 0; // Grab the 80211 info, compare, bail kis_ieee80211_packinfo *packinfo; if ((packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211))) == NULL) return 0; if (packinfo->corrupt) return 0; if (packinfo->type != packet_data || (packinfo->subtype != packet_sub_data && packinfo->subtype != packet_sub_data_qos_data)) return 0; // No need to look at data thats already been decoded if (packinfo->cryptset == 0 || packinfo->decrypted == 1) return 0; // Grab the 80211 frame, if that doesn't exist, grab the link frame kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } // If we don't have a dot11 frame, throw it away if (chunk->dlt != KDLT_IEEE802_11) return 0; // Bail if we can't find a key match macmap::iterator bwmitr = wepkeys.find(packinfo->bssid_mac); if (bwmitr == wepkeys.end()) return 0; manglechunk = DecryptWEP(packinfo, chunk, (*bwmitr->second)->key, (*bwmitr->second)->len, wep_identity); if (manglechunk == NULL) { (*bwmitr->second)->failed++; return 0; } (*bwmitr->second)->decrypted++; // printf("debug - flagging packet as decrypted\n"); packinfo->decrypted = 1; in_pack->insert(_PCM(PACK_COMP_MANGLEFRAME), manglechunk); return 1; } void KisBuiltinDissector::AddWepKey(mac_addr bssid, uint8_t *key, unsigned int len, int temp) { if (len > WEPKEY_MAX) return; wep_key_info *winfo = new wep_key_info; winfo->decrypted = 0; winfo->failed = 0; winfo->bssid = bssid; winfo->fragile = temp; winfo->len = len; memcpy(winfo->key, key, len); // Replace exiting ones if (wepkeys.find(winfo->bssid) != wepkeys.end()) { delete wepkeys[winfo->bssid]; wepkeys[winfo->bssid] = winfo; return; } wepkeys.insert(winfo->bssid, winfo); } int KisBuiltinDissector::cmd_listwepkeys(CLIENT_PARMS) { if (client_wepkey_allowed == 0) { snprintf(errstr, 1024, "Server does not allow clients to fetch keys"); return -1; } if (wepkeys.size() == 0) { snprintf(errstr, 1024, "Server has no WEP keys"); return -1; } if (_NPM(PROTO_REF_WEPKEY) < 0) { snprintf(errstr, 1024, "Unable to find WEPKEY protocol"); return -1; } for (macmap::iterator wkitr = wepkeys.begin(); wkitr != wepkeys.end(); wkitr++) { globalreg->kisnetserver->SendToClient(in_clid, _NPM(PROTO_REF_WEPKEY), (void *) wkitr->second, NULL); } return 1; } int KisBuiltinDissector::cmd_addwepkey(CLIENT_PARMS) { if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal addwepkey request"); return -1; } vector keyvec = StrTokenize((*parsedcmdline)[1].word, ","); if (keyvec.size() != 2) { snprintf(errstr, 1024, "Illegal addwepkey request"); return -1; } mac_addr bssid = keyvec[0].c_str(); if (bssid.error) { snprintf(errstr, 1024, "Illegal BSSID for addwepkey"); return -1; } unsigned char key[WEPKEY_MAX]; int len = Hex2UChar((unsigned char *) keyvec[1].c_str(), key); AddWepKey(bssid, key, len, 1); snprintf(errstr, 1024, "Added key %s length %d for BSSID %s", (*parsedcmdline)[0].word.c_str(), len, bssid.Mac2String().c_str()); _MSG(errstr, MSGFLAG_INFO); return 1; } int KisBuiltinDissector::cmd_delwepkey(CLIENT_PARMS) { if (client_wepkey_allowed == 0) { snprintf(errstr, 1024, "Server does not allow clients to modify keys"); return -1; } if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal delwepkey command"); return -1; } mac_addr bssid_mac = (*parsedcmdline)[0].word.c_str(); if (bssid_mac.error) { snprintf(errstr, 1024, "Illegal delwepkey bssid"); return -1; } if (wepkeys.find(bssid_mac) == wepkeys.end()) { snprintf(errstr, 1024, "Unknown delwepkey bssid"); return -1; } delete wepkeys[bssid_mac]; wepkeys.erase(bssid_mac); snprintf(errstr, 1024, "Deleted key for BSSID %s", bssid_mac.Mac2String().c_str()); _MSG(errstr, MSGFLAG_INFO); return 1; } int KisBuiltinDissector::basicstring_dissector(kis_packet *in_pack) { if (dissect_strings == 0) return 0; kis_string_info *stringinfo = NULL; vector parsed_strings; if (in_pack->error) return 0; // Grab the 80211 info, compare, bail kis_ieee80211_packinfo *packinfo; if ((packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211))) == NULL) return 0; if (packinfo->corrupt) return 0; if (packinfo->type != packet_data || (packinfo->subtype != packet_sub_data && packinfo->subtype != packet_sub_data_qos_data)) return 0; // If it's encrypted and hasn't been decrypted, we can't do anything // smart with it, so toss. if (packinfo->cryptset != 0 && packinfo->decrypted == 0) return 0; if (dissect_all_strings == 0 && dissect_strings) { if (string_nets.find(packinfo->bssid_mac) == string_nets.end() && string_nets.find(packinfo->source_mac) == string_nets.end() && string_nets.find(packinfo->dest_mac) == string_nets.end()) { return 0; } } // Grab the mangled frame if we have it, then try to grab up the list of // data types and die if we can't get anything kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } } // If we don't have a dot11 frame, throw it away if (chunk->dlt != KDLT_IEEE802_11) return 0; // Blow up on no content if (packinfo->header_offset > chunk->length) return 0; string str; int pos = 0; int printable = 0; for (unsigned int x = packinfo->header_offset; x < chunk->length; x++) { if (printable && !isprint(chunk->data[x]) && pos != 0) { if (pos > 4 && string_filter->RunFilter(packinfo->bssid_mac, packinfo->source_mac, packinfo->dest_mac) == 0 && string_filter->RunPcreFilter(str) == 0) { str = MungeToPrintable(str); // Send it to the clients string_proto_info nfo; nfo.text = str; nfo.bssid = packinfo->bssid_mac; nfo.source = packinfo->source_mac; nfo.dest = packinfo->dest_mac; globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_STRING), (void *) &nfo); // Cache it in the packet parsed_strings.push_back(str); } str = ""; pos = 0; printable = 0; } else if (isprint(chunk->data[x])) { str += (char) chunk->data[x]; pos++; printable = 1; } } if (parsed_strings.size() <= 0) return 0; stringinfo = (kis_string_info *) in_pack->fetch(_PCM(PACK_COMP_STRINGS)); if (stringinfo == NULL) { stringinfo = new kis_string_info; in_pack->insert(_PCM(PACK_COMP_STRINGS), stringinfo); } stringinfo->extracted_strings = parsed_strings; return 1; } void KisBuiltinDissector::SetStringExtract(int in_extr) { if (in_extr == 0 && dissect_strings == 2) { _MSG("SetStringExtract(): String dissection cannot be disabled because " "it is required by another active component.", MSGFLAG_ERROR); return; } // If we're setting the extract here, we have to turn it on for all BSSIDs dissect_strings = in_extr; dissect_all_strings = in_extr; } int KisBuiltinDissector::cmd_strings(CLIENT_PARMS) { // FIXME: write this if (parsedcmdline->size() < 1) { snprintf(errstr, 1024, "Illegal string request"); _MSG(errstr, MSGFLAG_ERROR); return -1; } int req; if (sscanf(((*parsedcmdline)[0]).word.c_str(), "%d", &req) != 1) { snprintf(errstr, 1024, "Illegal string request"); _MSG(errstr, MSGFLAG_ERROR); return -1; } if (dissect_strings == 2) { if (req == 0) _MSG("String dissection cannot be disabled because it is required " "by another component", MSGFLAG_INFO); return 1; } if (parsedcmdline->size() > 1) { mac_addr ma = mac_addr((*parsedcmdline)[0].word.c_str()); if (ma.error) { snprintf(errstr, 1024, "String dissection, got invalid MAC address"); _MSG(errstr, MSGFLAG_ERROR); return -1; } if (req) { string_nets.insert(ma, 1); _MSG("String dissection turned on for " + ma.Mac2String(), MSGFLAG_INFO); } else { string_nets.erase(ma); _MSG("String dissection turned off for " + ma.Mac2String(), MSGFLAG_INFO); } } else { if (req) { _MSG("String dissection from data frames enabled", MSGFLAG_INFO); dissect_all_strings = 1; } else { _MSG("String dissection from data frames disabled", MSGFLAG_INFO); dissect_all_strings = 0; } } dissect_strings = req; return 1; } int KisBuiltinDissector::cmd_stringsfilter(CLIENT_PARMS) { if (parsedcmdline->size() != 1) { snprintf(errstr, 1024, "Illegal addstringsfilter request"); _MSG(errstr, MSGFLAG_ERROR); return -1; } if (string_filter->AddFilterLine((*parsedcmdline)[0].word) < 0) { snprintf(errstr, 1024, "Failed to insert strings filter"); _MSG(errstr, MSGFLAG_ERROR); return -1; } _MSG("Added string filter '" + (*parsedcmdline)[0].word + "'", MSGFLAG_INFO); return 1; } kismet-2013-03-R1b/kis_panel_sort.h0000664000175000017500000001635412124602454016651 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_SORT_H__ #define __KIS_PANEL_SORT_H__ #include "config.h" #include "kis_panel_network.h" #include "kis_panel_frontend.h" class KisNetlist_Sort_Type { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->type < ym->type; } }; class KisNetlist_Sort_Channel { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->channel < ym->channel; } }; class KisNetlist_Sort_First { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->first_time < ym->first_time; } }; class KisNetlist_Sort_FirstDesc { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->first_time > ym->first_time; } }; class KisNetlist_Sort_Last { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->last_time < ym->last_time; } }; class KisNetlist_Sort_LastDesc { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->last_time > ym->last_time; } }; class KisNetlist_Sort_Bssid { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return xm->bssid < ym->bssid; } }; class KisNetlist_Sort_Ssid { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; if (xm->lastssid == NULL || ym->lastssid == NULL) return 0; return xm->lastssid->ssid < ym->lastssid->ssid; } }; class KisNetlist_Sort_Sdbm { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL ) return 0; if (time(0) - xm->last_time > 5) return 0; if (time(0) - ym->last_time > 5) return 1; return xm->snrdata.last_signal_dbm > ym->snrdata.last_signal_dbm; } }; class KisNetlist_Sort_Packets { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return (xm->llc_packets + xm->data_packets) < (ym->llc_packets + ym->data_packets); } }; class KisNetlist_Sort_PacketsDesc { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; return (xm->llc_packets + xm->data_packets) > (ym->llc_packets + ym->data_packets); } }; class KisNetlist_Sort_Crypt { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; if (xm->lastssid == NULL || ym->lastssid == NULL) return 0; return (xm->lastssid->cryptset) < (ym->lastssid->cryptset); } }; class KisNetlist_Sort_Clients { public: inline bool operator()(Kis_Display_NetGroup *x, Kis_Display_NetGroup *y) const { Netracker::tracked_network *xm = x->FetchNetwork(); Netracker::tracked_network *ym = y->FetchNetwork(); if (xm == NULL || ym == NULL) return 0; if (xm == NULL || ym == NULL) return 0; return (xm->client_map.size()) < (ym->client_map.size()); } }; class KisClientlist_Sort_First { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->first_time < y.cli->first_time; } }; class KisClientlist_Sort_FirstDesc { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->first_time > y.cli->first_time; } }; class KisClientlist_Sort_Last { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->last_time < y.cli->last_time; } }; class KisClientlist_Sort_LastDesc { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->last_time > y.cli->last_time; } }; class KisClientlist_Sort_Mac { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->mac < y.cli->mac; } }; class KisClientlist_Sort_Type { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return x.cli->type < y.cli->type; } }; class KisClientlist_Sort_Packets { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return (x.cli->llc_packets + x.cli->data_packets) < (y.cli->llc_packets + x.cli->data_packets); } }; class KisClientlist_Sort_PacketsDesc { public: inline bool operator()(Kis_Clientlist::display_client x, Kis_Clientlist::display_client y) const { return (x.cli->llc_packets + x.cli->data_packets) > (y.cli->llc_packets + x.cli->data_packets); } }; #endif kismet-2013-03-R1b/kis_droneframe.h0000664000175000017500000002614112124602454016620 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISDRONEFRAME_H__ #define __KISDRONEFRAME_H__ #include "config.h" #include #include "util.h" #include "globalregistry.h" #include "messagebus.h" #include "netframework.h" #include "packetchain.h" #include "packetsourcetracker.h" // Network stream protocol used for Drones. // Designed to be future-proof so that drone and server versions will be able // to co-mingle, instead of breaking all the users every time we find a field // we have to add. // // Future-proofing is accomplished via nested bitfields for each component and // subcomponent. // // uint16 is preferred over uint8 to prevent gaps in the struct packs // Forward prototype class KisDroneFramework; #define KIS_DRONE_VERSION 1 #define DRONEBIT(n) (1 << n) // Messagebus subscriber to pass data to the client class KisDroneframe_MessageClient : public MessageClient { public: KisDroneframe_MessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { }; virtual ~KisDroneframe_MessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; // Drone protocol const uint32_t DroneSentinel = 0xDEADBEEF; // Drone commands that determine the type of packet this is #define DRONE_CMDNUM_NULL 0 #define DRONE_CMDNUM_HELO 1 #define DRONE_CMDNUM_STRING 2 #define DRONE_CMDNUM_CAPPACKET 3 #define DRONE_CMDNUM_CHANNELSET 4 #define DRONE_CMDNUM_SOURCE 5 #define DRONE_CMDNUM_REPORT 6 // Size-neutral container for a uuid struct drone_trans_uuid { uint32_t time_low; uint16_t time_mid; uint16_t time_hi; uint16_t clock_seq; uint8_t node[6]; } __attribute__((__packed__)); #define DRONE_CONV_UUID(x, y) \ ({ \ (y)->time_low = kis_hton32(*((x).time_low)); \ (y)->time_mid = kis_hton16(*((x).time_mid)); \ (y)->time_hi = kis_hton16(*((x).time_hi)); \ (y)->clock_seq = kis_hton16(*((x).clock_seq)); \ memcpy((y)->node, (x).node, 6); \ }) #define UUID_CONV_DRONE(x, y) \ ({ \ (y).GenerateStoredUUID(kis_ntoh32((x)->time_low), \ kis_ntoh16((x)->time_mid), \ kis_ntoh16((x)->time_hi), \ kis_ntoh16((x)->clock_seq), \ (x)->node); \ }) // Size-neutral container for doubles struct drone_trans_double { uint32_t mantissal; uint32_t mantissah; uint16_t exponent; uint16_t sign; } __attribute__((__packed__)); #define DRONE_CONV_DOUBLE(x, y) \ ({ \ ieee_double_t *locfl = (ieee_double_t *) &(x); \ (y)->mantissal = kis_hton32(locfl->mantissal); \ (y)->mantissah = kis_hton32(locfl->mantissah); \ (y)->exponent = kis_hton16(locfl->exponent); \ (y)->sign = kis_hton16(locfl->sign); \ }) #define DOUBLE_CONV_DRONE(x, y) \ ({ \ ieee_double_t *locfl = (ieee_double_t *) &(x); \ (locfl)->mantissal = kis_ntoh32((y)->mantissal); \ (locfl)->mantissah = kis_ntoh32((y)->mantissah); \ (locfl)->exponent = kis_ntoh16((y)->exponent); \ (locfl)->sign = kis_ntoh16((y)->sign); \ }) // Packet header stuck on the beginning of everything struct drone_packet { uint32_t sentinel; uint32_t drone_cmdnum; uint32_t data_len; uint8_t data[0]; } __attribute__((__packed__)); // Basic hello packet struct drone_helo_packet { // Increment when we break the protocol in big ways uint32_t drone_version; // Version string of the kismet server hosting this uint8_t kismet_version[32]; // Arbitrary name of the drone/server hosting this uint8_t host_name[32]; } __attribute__((__packed__)); // String packet for text struct drone_string_packet { uint32_t msg_flags; uint32_t msg_len; char msg[0]; } __attribute__((__packed__)); // Channel set command packet (one channel sets chan, multiple sets vector) // OR if it comes FROM the drone, it indicates the current set of channels used // and the state of channel hopping. How a set command is treated depends on // the commands set. #define DRONE_CHANNELSET_UUID 0 #define DRONE_CHANNELSET_CMD 1 #define DRONE_CHANNELSET_CURCH 2 #define DRONE_CHANNELSET_HOP 3 #define DRONE_CHANNELSET_NUMCH 4 #define DRONE_CHANNELSET_CHANNELS 5 #define DRONE_CHANNELSET_CHANNELSDWELL 6 #define DRONE_CHANNELSET_HOPRATE 7 #define DRONE_CHANNELSET_HOPDWELL 8 // Commands for the channelset command #define DRONE_CHS_CMD_NONE 0 #define DRONE_CHS_CMD_SETHOP 1 #define DRONE_CHS_CMD_SETVEC 2 #define DRONE_CHS_CMD_SETCUR 3 #define DRONE_CHS_CMD_SETHOPDWELL 4 struct drone_channelset_packet { uint16_t channelset_hdr_len; uint32_t channelset_content_bitmap; drone_trans_uuid uuid; uint16_t command; uint16_t cur_channel; uint16_t channel_hop; uint16_t num_channels; /* Updated, breaks unreleased compat */ struct chandata_t { union { struct { // Highest bit (1 << 15) == 0 if channel uint16_t channel; uint16_t dwell; } chan_t; struct { // Highest bit (1 << 15) == 1 if range uint16_t start; uint16_t end; uint16_t width; uint16_t iter; } range_t; } u; } chandata[IPC_SOURCE_MAX_CHANS]; /* uint16_t channels[IPC_SOURCE_MAX_CHANS]; uint16_t channels_dwell[IPC_SOURCE_MAX_CHANS]; */ uint16_t channel_rate; uint16_t channel_dwell; } __attribute__((__packed__)); // Source record #define DRONE_SRC_UUID 0 #define DRONE_SRC_INVALID 1 #define DRONE_SRC_NAMESTR 2 #define DRONE_SRC_INTSTR 3 #define DRONE_SRC_TYPESTR 4 #define DRONE_SRC_CHANHOP 5 #define DRONE_SRC_CHANNELDWELL 6 #define DRONE_SRC_CHANNELRATE 7 struct drone_source_packet { uint16_t source_hdr_len; uint32_t source_content_bitmap; drone_trans_uuid uuid; // Kill this source, the rest of the data is empty uint16_t invalidate; // Null-terminated strings uint8_t name_str[16]; uint8_t interface_str[16]; uint8_t type_str[16]; uint8_t channel_hop; uint16_t channel_dwell; uint16_t channel_rate; } __attribute__((__packed__)); // Source report record #define DRONE_REPORT_UUID 0 #define DRONE_REPORT_FLAGS 1 #define DRONE_REPORT_HOP_TM_SEC 2 #define DRONE_REPORT_HOP_TM_USEC 3 struct drone_report_packet { uint16_t report_hdr_len; uint32_t report_content_bitmap; drone_trans_uuid uuid; uint8_t flags; uint32_t hop_tm_sec; uint32_t hop_tm_usec; } __attribute__((__packed__)); #define DRONE_REPORT_FLAG_NONE 0 #define DRONE_REPORT_FLAG_ERROR 128 // Bitmap fields for radio headers #define DRONE_RADIO_ACCURACY 0 #define DRONE_RADIO_FREQ_MHZ 1 #define DRONE_RADIO_SIGNAL_DBM 2 #define DRONE_RADIO_NOISE_DBM 3 #define DRONE_RADIO_CARRIER 4 #define DRONE_RADIO_ENCODING 5 #define DRONE_RADIO_DATARATE 6 #define DRONE_RADIO_SIGNAL_RSSI 7 #define DRONE_RADIO_NOISE_RSSI 8 // Radiotap-style header of radio data struct drone_capture_sub_radio { uint16_t radio_hdr_len; uint32_t radio_content_bitmap; uint16_t radio_accuracy; uint16_t radio_freq_mhz; int16_t radio_signal_dbm; int16_t radio_noise_dbm; uint32_t radio_carrier; uint32_t radio_encoding; uint32_t radio_datarate; int16_t radio_signal_rssi; int16_t radio_noise_rssi; } __attribute__((__packed__)); // Bitmap fields for gps headers #define DRONE_GPS_FIX 0 #define DRONE_GPS_LAT 1 #define DRONE_GPS_LON 2 #define DRONE_GPS_ALT 3 #define DRONE_GPS_SPD 4 #define DRONE_GPS_HEADING 5 // Radiotap-style header of GPS data struct drone_capture_sub_gps { uint16_t gps_hdr_len; uint32_t gps_content_bitmap; uint16_t gps_fix; drone_trans_double gps_lat; drone_trans_double gps_lon; drone_trans_double gps_alt; drone_trans_double gps_spd; drone_trans_double gps_heading; } __attribute__((__packed__)); // Bitmap fields for eitht11 subs #define DRONE_DATA_UUID 0 #define DRONE_DATA_PACKLEN 1 #define DRONE_DATA_TVSEC 2 #define DRONE_DATA_TVUSEC 3 #define DRONE_DATA_DLT 4 // Capture data struct drone_capture_sub_data { uint16_t data_hdr_len; uint32_t data_content_bitmap; drone_trans_uuid uuid; uint16_t packet_len; uint64_t tv_sec; uint64_t tv_usec; uint32_t dlt; uint8_t packdata[0]; // Alias to the trailing packet data } __attribute__((__packed__)); #define DRONE_CONTENT_RADIO 0 #define DRONE_CONTENT_GPS 1 #define DRONE_CONTENT_FCS 2 #define DRONE_CONTENT_IEEEPACKET 31 // Capture packet made of multiple other sub components // content[0] format: // Bitmap // Packet offset // --- Content --- // Radio header // GPS header // --- // Eight11 header // Raw packet data struct drone_capture_packet { uint32_t cap_content_bitmap; uint32_t cap_packet_offset; // This will be filled with a subset of (radio|gps|packet) based // on the content bitmap uint8_t content[0]; } __attribute__((__packed__)); // Callbacks #define DRONE_CMD_PARMS GlobalRegistry *globalreg, const drone_packet *data, \ const void *auxptr typedef int (*DroneCmdCallback)(DRONE_CMD_PARMS); // Drone framework for sending data class KisDroneFramework : public ServerFramework { public: KisDroneFramework(); KisDroneFramework(GlobalRegistry *in_globalreg); virtual ~KisDroneFramework(); // Activate the setup int Activate(); virtual int Accept(int in_fd); virtual int ParseData(int in_fd); virtual int KillConnection(int in_fd); // Handle a buffer drain on a client virtual int BufferDrained(int in_fd); // Usage static void Usage(char *name); // Add a command virtual int RegisterDroneCmd(uint32_t in_cmdid, DroneCmdCallback in_callback, void *in_aux); virtual int RemoveDroneCmd(uint32_t in_cmdid); // Send text down the connection virtual int SendText(int in_cl, string in_text, int flags); virtual int SendAllText(string in_text, int flags); // Chain handler virtual int chain_handler(kis_packet *in_pack); // Timer handler virtual int time_handler(); // AddSource handler... virtual void sourceact_handler(pst_packetsource *src, int action, int flags); // Send a frame virtual int SendPacket(int in_cl, drone_packet *in_pack); virtual int SendAllPacket(drone_packet *in_pack); // Send a source record virtual int SendSource(int in_cl, pst_packetsource *in_int, int invalid); virtual int SendAllSource(pst_packetsource *in_int, int invalid); // Send a source report virtual int SendSourceReport(int in_cl, pst_packetsource *in_int); virtual int SendAllSourceReport(pst_packetsource *in_int); // Send a channel record virtual int SendChannels(int in_cl, pst_packetsource *in_int); virtual int SendAllChannels(pst_packetsource *in_int); virtual int channel_handler(const drone_packet *in_pack); struct drone_cmd_rec { void *auxptr; DroneCmdCallback callback; }; protected: // Messagebus client KisDroneframe_MessageClient *kisdrone_msgcli; // Server type (0 = tcp...) int server_type; int eventid; map drone_cmd_map; }; #endif kismet-2013-03-R1b/kis_panel_plugin.h0000664000175000017500000000326312124602454017153 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef __KIS_PANEL_PLUGIN_H__ #define __KIS_PANEL_PLUGIN_H__ /* * Kismet panel frontend plugin data * * This class is similar to the global registry. It exports required * data from inside various panel frontends which plugins need access * to to get network lists, create panels, or add themselves to the * plugin menu */ #include "globalregistry.h" #include class KisPanelInterface; class Kis_Panel; class Kis_Main_Panel; class KisPanelPluginData { public: KisPanelInterface *kpinterface; Kis_Main_Panel *mainpanel; GlobalRegistry *globalreg; void *pluginaux; }; /* Plugin hook definition. This function is the only function which will * be called on a panel plugin. The plugin is then responsible for registering * itself with the system. */ typedef int (*panel_plugin_hook)(GlobalRegistry *, KisPanelPluginData *); struct panel_plugin_meta { string filename; string objectname; void *dlfileptr; }; #endif kismet-2013-03-R1b/psutils.cc0000664000175000017500000000346312124602454015473 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include int FindProcess(string in_proc, string in_option) { #ifdef SYS_LINUX DIR *procdir; struct dirent *pid; FILE *pfile; string path, targ; int c; vector parsed; if ((procdir = opendir("/proc")) == NULL) return 0; while ((pid = readdir(procdir)) != NULL) { path = string("/proc/") + pid->d_name + string("/cmdline"); if ((pfile = fopen(path.c_str(), "r")) != NULL) { targ = ""; parsed.clear(); // this sucks while ((c = fgetc(pfile)) != EOF) { if (c == '\0') { parsed.push_back(targ); targ = ""; continue; } targ += c; } fclose(pfile); if (parsed.size() <= 0) continue; if (parsed[0].find(in_proc) != string::npos) { for (unsigned int x = 1; x < parsed.size(); x++) { if (parsed[x].find(in_option) != string::npos) { closedir(procdir); return 1; } } } } } closedir(procdir); #endif return 0; } kismet-2013-03-R1b/uuid.h0000664000175000017500000001341412124602454014575 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __UUID_H__ #define __UUID_H__ #include "config.h" #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include "util.h" // UUID Generation // From e2fstools, Theodore Ts'o /* Assume that the gettimeofday() has microsecond granularity */ #define MAX_ADJUSTMENT 10 class uuid { public: uuid() { memset(uuid_block, 0, 16); time_low = (uint32_t *) &(uuid_block[0]); time_mid = (uint16_t *) &(uuid_block[4]); time_hi = (uint16_t *) &(uuid_block[6]); clock_seq = (uint16_t *) &(uuid_block[8]); node = &(uuid_block[10]); error = 1; } uuid(const string in) { memset(uuid_block, 0, 16); time_low = (uint32_t *) &(uuid_block[0]); time_mid = (uint16_t *) &(uuid_block[4]); time_hi = (uint16_t *) &(uuid_block[6]); clock_seq = (uint16_t *) &(uuid_block[8]); node = &(uuid_block[10]); unsigned int ln[6]; unsigned int ltl, ltm, lth, lcs; if (sscanf(in.c_str(), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", <l, <m, <h, &lcs, &ln[0], &ln[1], &ln[2], &ln[3], &ln[4], &ln[5]) != 10) { error = 1; return; } error = 0; *time_low = ltl; *time_mid = ltm; *time_hi = lth; *clock_seq = lcs; for (unsigned int x = 0; x < 6; x++) { node[x] = ln[x]; } } uuid(uint8_t *in_node) { GenerateTimeUUID(in_node); } void GenerateTimeUUID(uint8_t *in_node) { uint32_t clock_mid; get_clock(&clock_mid, time_low, clock_seq); *clock_seq |= 0x8000; *time_mid = (uint16_t) clock_mid; *time_hi = ((clock_mid >> 16) & 0x0FFF) | 0x1000; memcpy(node, in_node, 6); error = 0; } void GenerateStoredUUID(uint32_t in_low, uint16_t in_mid, uint16_t in_hi, uint16_t in_seq, uint8_t *in_node) { *time_low = in_low; *time_mid = in_mid; *time_hi = in_hi; *clock_seq = in_seq; memcpy(node, in_node, 6); error = 0; } string UUID2String() { char ids[38]; snprintf(ids, 38, "%08x-%04hx-%04hx-%04hx-%02hx%02hx%02hx%02hx%02hx%02hx", (unsigned int) *time_low, *time_mid, *time_hi, *clock_seq, node[0], node[1], node[2], node[3], node[4], node[5]); return string(ids); } inline bool operator== (const uuid& op) const { if (memcmp(uuid_block, op.uuid_block, 16) == 0) return 1; return 0; } inline bool operator!= (const uuid& op) const { if (memcmp(uuid_block, op.uuid_block, 16) != 0) return 1; return 0; } inline bool operator<= (const uuid& op) const { int ret = memcmp(uuid_block, op.uuid_block, 16); if (ret <= 0) return 1; return 0; } inline bool operator< (const uuid& op) const { int ret = memcmp(uuid_block, op.uuid_block, 16); if (ret < 0) return 1; return 0; } uuid& operator= (const uuid& op) { memcpy(uuid_block, op.uuid_block, 16); error = op.error; return *this; } uint8_t uuid_block[16]; uint32_t *time_low; uint16_t *time_mid; uint16_t *time_hi; uint16_t *clock_seq; uint8_t *node; int error; protected: int get_random_fd() { struct timeval tv; static int fd = -2; int i; if (fd == -2) { gettimeofday(&tv, 0); fd = open("/dev/urandom", O_RDONLY); if (fd == -1) fd = open("/dev/random", O_RDONLY | O_NONBLOCK); srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); } /* Crank the random number generator a few times */ gettimeofday(&tv, 0); for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) rand(); return fd; } void get_random_bytes(void *buf, int nbytes) { int i, n = nbytes, fd = get_random_fd(); int lose_counter = 0; unsigned char *cp = (unsigned char *) buf; if (fd >= 0) { while (n > 0) { i = read(fd, cp, n); if (i <= 0) { if (lose_counter++ > 16) break; continue; } n -= i; cp += i; lose_counter = 0; } } for (cp = (unsigned char *) buf, i = 0; i < nbytes; i++) *cp++ ^= (rand() >> 7) & 0xFF; close(fd); return; } int get_clock(uint32_t *in_clock_high, uint32_t *in_clock_low, uint16_t *in_clock_seq) { static int adjustment = 0; static struct timeval last = {0, 0}; static uint16_t clock_seq; struct timeval tv; unsigned long long clock_reg; try_again: gettimeofday(&tv, 0); if ((last.tv_sec == 0) && (last.tv_usec == 0)) { get_random_bytes(&clock_seq, sizeof(clock_seq)); clock_seq &= 0x3FFF; last = tv; last.tv_sec--; } if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) { clock_seq = (clock_seq+1) & 0x3FFF; adjustment = 0; last = tv; } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) { if (adjustment >= MAX_ADJUSTMENT) goto try_again; adjustment++; } else { adjustment = 0; last = tv; } clock_reg = tv.tv_usec * 10 + adjustment; clock_reg += ((unsigned long long) tv.tv_sec) * 10000000; clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; *in_clock_high = clock_reg >> 32; *in_clock_low = (uint32_t) clock_reg; *in_clock_seq = clock_seq; return 0; } }; #endif kismet-2013-03-R1b/drone_kisnetframe.cc0000664000175000017500000000563412124602454017471 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Stubbed out class for the drone to link. Many components expect the * netframe to be present, but the drone doesn't use it. Linking this in * will stub out all the functions that the components expect. */ #include "config.h" #include "util.h" #include "configfile.h" #include "packet.h" #include "packetsourcetracker.h" #include "packetchain.h" #include "kis_netframe.h" #include "tcpserver.h" #include "getopt.h" KisNetFramework::KisNetFramework() { return; } void KisNetFramework::Usage(char *name) { return; } KisNetFramework::KisNetFramework(GlobalRegistry *in_globalreg) { return; } int KisNetFramework::Shutdown() { return 0; } int KisNetFramework::Activate() { return 0; } KisNetFramework::~KisNetFramework() { return; } int KisNetFramework::Accept(int in_fd) { return 0; } int KisNetFramework::BufferDrained(int in_fd) { return 0; } int KisNetFramework::ParseData(int in_fd) { return 0; } int KisNetFramework::KillConnection(int in_fd) { return 0; } int KisNetFramework::RegisterClientCommand(string in_cmdword, ClientCommand in_cmd, void *in_auxptr) { return 0; } int KisNetFramework::RemoveClientCommand(string in_cmdword) { return 0; } int KisNetFramework::SendToClient(int in_fd, int in_refnum, const void *in_data, kis_protocol_cache *in_cache) { return 0; } int KisNetFramework::SendToAll(int in_refnum, const void *in_data) { return 0; } int KisNetFramework::RegisterProtocol(string in_header, int in_required, int in_cache, const char **in_fields, int (int_printer)(PROTO_PARMS), void (*in_enable)(PROTO_ENABLE_PARMS), void *in_auxdata) { return 0; } int KisNetFramework::RemoveProtocol(int in_protoref) { return 0; } int KisNetFramework::FetchProtocolRef(string in_header) { return 0; } KisNetFramework::server_protocol *KisNetFramework::FetchProtocol(int in_ref) { return 0; } int KisNetFramework::FetchNumClientRefs(int in_refnum) { return 0; } int KisNetFramework::FetchNumClients() { return 0; } void KisNetFramework::AddProtocolClient(int in_fd, int in_refnum, vector in_fields) { return; } void KisNetFramework::DelProtocolClient(int in_fd, int in_refnum) { return; } kismet-2013-03-R1b/channeltracker.cc0000664000175000017500000001666712124602454016766 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include "util.h" #include "packetsource.h" #include "configfile.h" #include "channeltracker.h" #include "packetsourcetracker.h" enum CHANNEL_fields { CHANNEL_channel, CHANNEL_time_on, CHANNEL_packets, CHANNEL_packets_delta, CHANNEL_usec_used, CHANNEL_bytes, CHANNEL_bytes_delta, CHANNEL_networks, CHANNEL_maxsignal_dbm, CHANNEL_maxsignal_rssi, CHANNEL_maxnoise_dbm, CHANNEL_maxnoise_rssi, CHANNEL_activenetworks, CHANNEL_maxfield }; const char *CHANNEL_fields_text[] = { "channel", "time_on", "packets", "packetsdelta", "usecused", "bytes", "bytesdelta", "networks", "maxsignal_dbm", "maxsignal_rssi", "maxnoise_dbm", "maxnoise_rssi", "activenetworks", NULL }; int ct_chan_hook(CHAINCALL_PARMS) { ((Channeltracker *) auxdata)->ChainHandler(in_pack); return 1; } int ct_channeltimer(TIMEEVENT_PARMS) { ((Channeltracker *) parm)->ChanTimer(); return 1; } void Protocol_CHANNEL_enable(PROTO_ENABLE_PARMS) { return; } int Protocol_CHANNEL(PROTO_PARMS) { Channeltracker::channel_record *chrec = (Channeltracker::channel_record *) data; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= CHANNEL_maxfield) { out_string += "Unknown field requested"; return -1; } if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case CHANNEL_channel: cache->Cache(fnum, IntToString(chrec->channel)); break; case CHANNEL_time_on: cache->Cache(fnum, IntToString(chrec->channel_time_on)); break; case CHANNEL_packets: cache->Cache(fnum, IntToString(chrec->packets)); break; case CHANNEL_packets_delta: cache->Cache(fnum, IntToString(chrec->packets_delta)); break; case CHANNEL_usec_used: cache->Cache(fnum, LongIntToString(chrec->usec_used)); break; case CHANNEL_bytes: cache->Cache(fnum, LongIntToString(chrec->bytes_seen)); break; case CHANNEL_bytes_delta: cache->Cache(fnum, LongIntToString(chrec->bytes_delta)); break; case CHANNEL_networks: cache->Cache(fnum, IntToString(chrec->seen_networks.size())); break; case CHANNEL_maxsignal_dbm: cache->Cache(fnum, IntToString(chrec->max_signal_dbm)); break; case CHANNEL_maxsignal_rssi: cache->Cache(fnum, IntToString(chrec->max_signal_rssi)); break; case CHANNEL_maxnoise_dbm: cache->Cache(fnum, IntToString(chrec->max_noise_dbm)); break; case CHANNEL_maxnoise_rssi: cache->Cache(fnum, IntToString(chrec->max_noise_rssi)); break; case CHANNEL_activenetworks: cache->Cache(fnum, IntToString(chrec->delta_networks.size())); break; } out_string += cache->GetCache(fnum) + " "; } return 1; } Channeltracker::Channeltracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: Channeltracker called before timetracker\n"); exit(1); } if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Channeltracker called before packetchain\n"); exit(1); } globalreg->packetchain->RegisterHandler(&ct_chan_hook, this, CHAINPOS_LOGGING, 0); chan_timer_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 2, NULL, 1, &ct_channeltimer, this); chan_proto_id = globalreg->kisnetserver->RegisterProtocol("CHANNEL", 0, 1, CHANNEL_fields_text, &Protocol_CHANNEL, &Protocol_CHANNEL_enable, this); } Channeltracker::~Channeltracker() { globalreg->timetracker->RemoveTimer(chan_timer_id); globalreg->packetchain->RemoveHandler(&ct_chan_hook, CHAINPOS_LOGGING); globalreg->kisnetserver->RemoveProtocol(chan_proto_id); } void Channeltracker::ChanTimer() { map *tick_map = globalreg->sourcetracker->FetchChannelTickMap(); // If we have more than 50 channels (arbitrary number) in the tick map, we're // probably processing a huge range, which means we won't include the tick // map - we'll only use the map of channels we've seen packets on. for (map::iterator x = tick_map->begin(); x != tick_map->end() && tick_map->size() < 50; ++x) { if (x->first == 0) continue; if (channel_map.find(x->first) == channel_map.end()) { channel_record *crec = new channel_record; channel_map[FreqToChan(x->first)] = crec; crec->channel = FreqToChan(x->first); } } for (map::iterator x = channel_map.begin(); x != channel_map.end(); ++x) { if (tick_map->find(x->first) != tick_map->end()) { x->second->channel_time_on = (*tick_map)[x->first] * (1000000 / SERVER_TIMESLICES_SEC); } else { x->second->channel_time_on = 0; } globalreg->kisnetserver->SendToAll(chan_proto_id, (void *) x->second); // Reset the deltas x->second->packets_delta = 0; x->second->bytes_delta = 0; x->second->usec_used = 0; x->second->delta_networks.clear(); x->second->sent_reset = 1; } } void Channeltracker::ChainHandler(kis_packet *in_pack) { kis_ieee80211_packinfo *packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211)); kis_layer1_packinfo *radioinfo = (kis_layer1_packinfo *) in_pack->fetch(_PCM(PACK_COMP_RADIODATA)); channel_record *crec = NULL; if (radioinfo == NULL) return; if (radioinfo->freq_mhz == 0) return; int channel = FreqToChan(radioinfo->freq_mhz); if (channel_map.find(channel) != channel_map.end()) { crec = channel_map[channel]; } else { crec = new channel_record; channel_map[channel] = crec; crec->channel = channel; } if (packinfo != NULL) { crec->bytes_seen += packinfo->datasize; crec->bytes_delta += packinfo->datasize; if (crec->seen_networks.find(packinfo->bssid_mac) == crec->seen_networks.end()) { crec->seen_networks.insert(packinfo->bssid_mac, 1); crec->delta_networks.insert(packinfo->bssid_mac, 1); } else if (crec->delta_networks.find(packinfo->bssid_mac) == crec->delta_networks.end()) { crec->delta_networks.insert(packinfo->bssid_mac, 1); } // Todo - fill in time handling } if ((radioinfo->signal_dbm > crec->max_signal_dbm && radioinfo->signal_dbm != 0) || crec->sent_reset) crec->max_signal_dbm = radioinfo->signal_dbm; if (radioinfo->signal_rssi > crec->max_signal_rssi || crec->sent_reset) crec->max_signal_rssi = radioinfo->signal_rssi; if ((radioinfo->noise_dbm > crec->max_noise_dbm && radioinfo->noise_dbm != 0) || crec->sent_reset) crec->max_noise_dbm = radioinfo->noise_dbm; if (radioinfo->noise_rssi > crec->max_noise_rssi || crec->sent_reset) crec->max_noise_rssi = radioinfo->noise_rssi; crec->packets++; crec->packets_delta++; crec->sent_reset = 0; } kismet-2013-03-R1b/dumpfile_nettxt.h0000664000175000017500000000232312124602454017037 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_NETTXT_H__ #define __DUMPFILE_NETTXT_H__ #include "config.h" #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "dumpfile.h" #include "netracker.h" // Net txt bulk logger class Dumpfile_Nettxt : public Dumpfile { public: Dumpfile_Nettxt(); Dumpfile_Nettxt(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Nettxt(); virtual int Flush(); protected: FILE *txtfile; }; #endif /* __dump... */ kismet-2013-03-R1b/netracker.h0000664000175000017500000004223512124602454015610 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __NETRACKER_H__ #define __NETRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "kis_netframe.h" #include "timetracker.h" #include "filtercore.h" #include "gpscore.h" #include "packet.h" #include "uuid.h" #include "configfile.h" #include "devicetracker.h" // Cache file versioning #define NETRACKER_SSIDCACHE_VERSION 2 #define NETRACKER_IPCACHE_VERSION 2 // Core network tracker hooks to call back into our core tracker // elements int kis_80211_netracker_hook(CHAINCALL_PARMS); int kis_80211_datatracker_hook(CHAINCALL_PARMS); // Timer event to update int NetrackerUpdateTimer(TIMEEVENT_PARMS); // Tcp server elements enum BSSID_fields { BSSID_bssid, BSSID_type, BSSID_llcpackets, BSSID_datapackets, BSSID_cryptpackets, BSSID_manuf, BSSID_channel, BSSID_firsttime, BSSID_lasttime, BSSID_atype, BSSID_rangeip, BSSID_netmaskip, BSSID_gatewayip, BSSID_gpsfixed, BSSID_minlat, BSSID_minlon, BSSID_minalt, BSSID_minspd, BSSID_maxlat, BSSID_maxlon, BSSID_maxalt, BSSID_maxspd, BSSID_signal_dbm, BSSID_noise_dbm, BSSID_minsignal_dbm, BSSID_minnoise_dbm, BSSID_maxsignal_dbm, BSSID_maxnoise_dbm, BSSID_signal_rssi, BSSID_noise_rssi, BSSID_minsignal_rssi, BSSID_minnoise_rssi, BSSID_maxsignal_rssi, BSSID_maxnoise_rssi, BSSID_bestlat, BSSID_bestlon, BSSID_bestalt, BSSID_agglat, BSSID_agglon, BSSID_aggalt, BSSID_aggpoints, BSSID_datasize, BSSID_tcnid, BSSID_tcmode, BSSID_tsat, BSSID_carrierset, BSSID_maxseenrate, BSSID_encodingset, BSSID_decrypted, BSSID_dupeiv, BSSID_bsstimestamp, BSSID_cdpdevice, BSSID_cdpport, BSSID_fragments, BSSID_retries, BSSID_newpackets, BSSID_freqmhz, BSSID_datacryptset, BSSID_maxfield }; enum SSID_fields { SSID_mac, SSID_checksum, SSID_type, SSID_ssid, SSID_beaconinfo, SSID_cryptset, SSID_cloaked, SSID_firsttime, SSID_lasttime, SSID_maxrate, SSID_beaconrate, SSID_packets, SSID_beacons, SSID_dot11d, SSID_maxfield }; enum CLIENT_fields { CLIENT_bssid, CLIENT_mac, CLIENT_type, CLIENT_firsttime, CLIENT_lasttime, CLIENT_manuf, CLIENT_llcpackets, CLIENT_datapackets, CLIENT_cryptpackets, CLIENT_gpsfixed, CLIENT_minlat, CLIENT_minlon, CLIENT_minalt, CLIENT_minspd, CLIENT_maxlat, CLIENT_maxlon, CLIENT_maxalt, CLIENT_maxspd, CLIENT_agglat, CLIENT_agglon, CLIENT_aggalt, CLIENT_aggpoints, CLIENT_signal_dbm, CLIENT_noise_dbm, CLIENT_minsignal_dbm, CLIENT_minnoise_dbm, CLIENT_maxsignal_dbm, CLIENT_maxnoise_dbm, CLIENT_signal_rssi, CLIENT_noise_rssi, CLIENT_minsignal_rssi, CLIENT_minnoise_rssi, CLIENT_maxsignal_rssi, CLIENT_maxnoise_rssi, CLIENT_bestlat, CLIENT_bestlon, CLIENT_bestalt, CLIENT_atype, CLIENT_ip, CLIENT_gatewayip, CLIENT_datasize, CLIENT_maxseenrate, CLIENT_encodingset, CLIENT_carrierset, CLIENT_decrypted, CLIENT_channel, CLIENT_fragments, CLIENT_retries, CLIENT_newpackets, CLIENT_freqmhz, CLIENT_cdpdevice, CLIENT_cdpport, CLIENT_dot11d, CLIENT_dhcphost, CLIENT_dhcpvendor, CLIENT_datacryptset, CLIENT_maxfield }; enum BSSIDSRC_fields { BSSIDSRC_bssid, BSSIDSRC_uuid, BSSIDSRC_lasttime, BSSIDSRC_numpackets, BSSIDSRC_signal_dbm, BSSIDSRC_noise_dbm, BSSIDSRC_minsignal_dbm, BSSIDSRC_minnoise_dbm, BSSIDSRC_maxsignal_dbm, BSSIDSRC_maxnoise_dbm, BSSIDSRC_signal_rssi, BSSIDSRC_noise_rssi, BSSIDSRC_minsignal_rssi, BSSIDSRC_minnoise_rssi, BSSIDSRC_maxsignal_rssi, BSSIDSRC_maxnoise_rssi, BSSIDSRC_maxfield }; enum CLISRC_fields { CLISRC_bssid, CLISRC_mac, CLISRC_uuid, CLISRC_lasttime, CLISRC_numpackets, CLISRC_signal_dbm, CLISRC_noise_dbm, CLISRC_minsignal_dbm, CLISRC_minnoise_dbm, CLISRC_maxsignal_dbm, CLISRC_maxnoise_dbm, CLISRC_signal_rssi, CLISRC_noise_rssi, CLISRC_minsignal_rssi, CLISRC_minnoise_rssi, CLISRC_maxsignal_rssi, CLISRC_maxnoise_rssi, CLISRC_maxfield }; enum NETTAG_fields { NETTAG_bssid, NETTAG_tag, NETTAG_value, NETTAG_maxfield }; enum CLITAG_fields { CLITAG_bssid, CLITAG_mac, CLITAG_tag, CLITAG_value, CLITAG_maxfield }; enum REMOVE_fields { REMOVE_bssid }; // Enums explicitly defined for the ease of client writers enum network_type { network_ap = 0, network_adhoc = 1, network_probe = 2, network_turbocell = 3, network_data = 4, network_mixed = 255, network_remove = 256 }; enum client_type { client_unknown = 0, client_fromds = 1, client_tods = 2, client_interds = 3, client_established = 4, client_adhoc = 5, client_remove = 6 }; enum ssid_type { ssid_beacon = 0, ssid_proberesp = 1, ssid_probereq = 2, ssid_file = 3, }; // Netracker itself class Netracker { public: // Forward defs class tracked_network; class tracked_client; struct source_data { source_data() { last_seen = 0; num_packets = 0; } uuid source_uuid; time_t last_seen; uint32_t num_packets; mac_addr bssid; mac_addr mac; kis_signal_data snrdata; }; // Advertised SSID data for multi-ssid networks // Each SSID advertised can have its own advertised limits struct adv_ssid_data { adv_ssid_data() { checksum = 0; type = ssid_beacon; mac = mac_addr(0); ssid = ""; beacon_info = ""; cryptset = 0; ssid_cloaked = 0; first_time = 0; last_time = 0; dirty = 0; maxrate = 0; beaconrate = 0; packets = 0; beacons = 0; dot11d_country = "XXX"; } inline adv_ssid_data& operator= (const adv_ssid_data& in) { checksum = in.checksum; type = in.type; mac = in.mac; ssid = in.ssid; ssid_cloaked = in.ssid_cloaked; beacon_info = in.beacon_info; cryptset = in.cryptset; first_time = in.first_time; last_time = in.last_time; dirty = in.dirty; maxrate = in.maxrate; beaconrate = in.beaconrate; packets = in.packets; beacons = in.beacons; dot11d_country = in.dot11d_country; dot11d_vec = in.dot11d_vec; dirty = in.dirty; return *this; } uint32_t checksum; ssid_type type; mac_addr mac; string ssid; string beacon_info; // Cryptset and decrypted uint64_t cryptset; // Is the SSID hidden int ssid_cloaked; // First and last times we saw this SSID time_t first_time; time_t last_time; // Advertised maximum rate double maxrate; // Beacon rate in # of beacons per second int beaconrate; // Number of packets seen advertising this ssid int packets; // Number of beacons seen in the last second (for calculating loss) int beacons; string dot11d_country; vector dot11d_vec; // SSID is dirty and should be resent int dirty; }; // Fwd def for our map class tracked_client; class ssid_alert_data { public: ssid_alert_data() { #ifdef HAVE_LIBPCRE ssid_re = NULL; ssid_study = NULL; #endif } string name; #ifdef HAVE_LIBPCRE pcre *ssid_re; pcre_extra *ssid_study; string filter; #endif string ssid; macmap allow_mac_map; }; class tracked_network { public: tracked_network() { type = network_ap; llc_packets = data_packets = crypt_packets = 0; channel = 0; bssid = mac_addr(0); decrypted = 0; last_time = first_time = 0; client_disconnects = 0; last_sequence = 0; bss_timestamp = 0; datasize = 0; dupeiv_packets = 0; dirty = 0; fragments = 0; retries = 0; new_packets = 0; groupptr = NULL; lastssid = NULL; alert = 0; data_cryptset = 0; } // What we last saw it as network_type type; mac_addr bssid; // Aggregate packet counts int llc_packets; int data_packets; int crypt_packets; string manuf; // Clients seen associated with this network - we don't need // to use a macmap since they'll all be unique/unmasked map client_map; // Advertised SSID data, often only 1 item map ssid_map; // Channel reported by packets int channel; // Last-seen frequency map freq_mhz_map; time_t last_time; time_t first_time; // Cryptset seen from data packets not linked to a SSID uint64_t data_cryptset; // One of the SSIDs decrypted? int decrypted; // GPS info kis_gps_data gpsdata; // SNR info kis_signal_data snrdata; // Guesstimated IP data kis_ip_data guess_ipdata; // state tracking elements // Number of client disconnects (decayed per second) int client_disconnects; // Last sequence value int last_sequence; // last BSS timestamp uint64_t bss_timestamp; // Amount of data seen uint64_t datasize; // Map of IVs seen (Is this a really bad idea for ram? Probably. Consider // nuking this if it can't be compressed somehow at runtime. Or make it a // config variable for people with ram to burn) map iv_map; // Number of duplicate IV counts int dupeiv_packets; string cdp_dev_id; string cdp_port_id; // Fragment and retries within the last second int fragments; int retries; // Number of packets since last tick int new_packets; // Network is dirty and should be pushed out int dirty; // Client pointers to do "stuff" void *groupptr; adv_ssid_data *lastssid; // Map of sources which have seen this network map source_map; // Alert triggered int alert; // Map of arbitrary tags associated with this network // Tags are case sensitive! map arb_tag_map; }; // Mini-client for counting global unique clients class tracked_mini_client { public: tracked_mini_client() { mac = mac_addr(0); last_bssid_mac = mac_addr(0); num_bssids = 0; } mac_addr mac; mac_addr last_bssid_mac; int num_bssids; }; class tracked_client { public: tracked_client() { type = client_unknown; mac = mac_addr(0); last_time = first_time = 0; decrypted = 0; channel = 0; llc_packets = data_packets = crypt_packets = 0; last_sequence = 0; datasize = 0; netptr = NULL; fragments = 0; retries = 0; new_packets = 0; dirty = 0; dot11d_country = "XXX"; data_cryptset = 0; } // DS detected type client_type type; // timestamps time_t last_time; time_t first_time; // Crypt and decrypt sets int decrypted; // MAC of client mac_addr mac; // MAC of network mac_addr bssid; // Last seen channel int channel; // Last seen frequency map freq_mhz_map; kis_gps_data gpsdata; kis_signal_data snrdata; // Individual packet counts int llc_packets; int data_packets; int crypt_packets; // Manufacturer info - MAC address key to the manuf map and score // for easy mapping string manuf; // Last sequence number seen int last_sequence; // Data cryptset uint64_t data_cryptset; // Amount of data seen uint64_t datasize; // Guesstimated IP data kis_ip_data guess_ipdata; // Fragments and retries for packet stats int fragments; int retries; // CDP tracking string cdp_dev_id; string cdp_port_id; // DHCP discovery tracking string dhcp_host, dhcp_vendor; // Packets since last push int new_packets; // Do we need to push an update? int dirty; // Probed ssid data map ssid_map; // Pointer to the network we belong to, for fast compares Netracker::tracked_network *netptr; // Map of sources which have seen this network map source_map; string dot11d_country; vector dot11d_vec; // Map of arbitrary tags associated with this network // Tags are case sensitive! map arb_tag_map; }; Netracker(); Netracker(GlobalRegistry *in_globalreg); ~Netracker(); int FetchNumNetworks(); int FetchNumPackets(); int FetchNumDatapackets(); int FetchNumCryptpackets(); int FetchNumErrorpackets(); int FetchNumFiltered(); int FetchNumClients(); int FetchNumLLCpackets(); int FetchPacketRate(); int AddFilter(string in_filter); int AddNetcliFilter(string in_filter); void SetNetworkTag(mac_addr in_net, string in_tag, string in_data, int in_persistent); void ClearNetworkTag(mac_addr in_net, string in_tag); string GetNetworkTag(mac_addr in_net, string in_tag); void SetClientTag(mac_addr in_net, mac_addr in_cli, string in_tag, string in_data, int in_persistent); void ClearClientTag(mac_addr in_net, mac_addr in_cli, string in_tag); string GetClientTag(mac_addr in_net, mac_addr in_cli, string in_tag); // Fetch the internal maps. Touching these is Bad. Should only be used when // the chain API is insufficient, like logging xml/net ascii const map FetchTrackedNets(); const map FetchProbeNets(); typedef map::iterator track_iter; typedef map::iterator client_iter; typedef map::iterator ipcache_iter; typedef map::iterator ssidcache_iter; typedef map::iterator client_mini_iter; static void Usage(char *argv); protected: GlobalRegistry *globalreg; int num_packets; int num_datapackets; int num_cryptpackets; int num_errorpackets; int num_filterpackets; int num_packetdelta; int num_llcpackets; // Actually handle the chain events int netracker_chain_handler(kis_packet *in_pack); int datatracker_chain_handler(kis_packet *in_pack); // Build a SSID record Netracker::adv_ssid_data *BuildAdvSSID(uint32_t ssid_csum, kis_ieee80211_packinfo *packinfo, kis_packet *in_pack); // Kick the timer event to update all the clients int TimerKick(); // Save SSID map void SaveSSID(); void SaveTags(); // Associate probes w/ networks int track_probenets; // All networks map tracked_map; // Probe association to network that owns it map probe_assoc_map; // Cached data map bssid_ip_map; map bssid_cloak_map; // Mini-client map for unique counting map client_mini_map; // Vector of dirty elements for pushing out to clients, quicker than // walking the map every tick vector dirty_net_vec; vector dirty_cli_vec; vector apspoof_vec; // Manufacturer maps /* macmap > ap_manuf_map; macmap > client_manuf_map; */ // Cache files paths and states string ssid_cache_path, ip_cache_path; int ssid_cache_track, ip_cache_track; // Alert references int alert_chan_ref, alert_dhcpcon_ref, alert_bcastdcon_ref, alert_airjackssid_ref, alert_wepflap_ref, alert_dhcpname_ref, alert_dhcpos_ref, alert_adhoc_ref, alert_ssidmatch_ref; // Timer refs int netrackereventid; // Command refs int addfiltercmd_ref, addnetclifiltercmd_ref, addnettagcmd_ref, delnettagcmd_ref, addclitagcmd_ref, delclitagcmd_ref; // Filter core for tracker FilterCore *track_filter; // Filter core for network client FilterCore *netcli_filter; // Nonglobal protocols int proto_ref_bssidsrc, proto_ref_clisrc, proto_ref_nettag, proto_ref_clitag; // SSID cloak file as a config ConfigFile *ssid_conf, *tag_conf; time_t conf_save; // Let the hooks call directly in friend int kis_80211_netracker_hook(CHAINCALL_PARMS); friend int kis_80211_datatracker_hook(CHAINCALL_PARMS); friend void Protocol_BSSID_enable(PROTO_ENABLE_PARMS); friend void Protocol_SSID_enable(PROTO_ENABLE_PARMS); friend void Protocol_CLIENT_enable(PROTO_ENABLE_PARMS); friend void Protocol_NETTAG_enable(PROTO_ENABLE_PARMS); friend void Protocol_CLITAG_enable(PROTO_ENABLE_PARMS); friend int NetrackerUpdateTimer(TIMEEVENT_PARMS); }; int Protocol_NETWORK(PROTO_PARMS); int Protocol_CLIENT(PROTO_PARMS); // BSSID int Protocol_REMOVE(PROTO_PARMS); void Protocol_NETWORK_enable(PROTO_ENABLE_PARMS); void Protocol_CLIENT_enable(PROTO_ENABLE_PARMS); int Netracker_Clicmd_ADDFILTER(CLIENT_PARMS); int Netracker_Clicmd_ADDNETCLIFILTER(CLIENT_PARMS); // Hooks into the packet component trackers class kis_netracker_netinfo : public packet_component { public: kis_netracker_netinfo() { self_destruct = 1; // OK to delete us, we're only a pointer container netref = NULL; } Netracker::tracked_network *netref; }; class kis_netracker_cliinfo : public packet_component { public: kis_netracker_cliinfo() { self_destruct = 1; // OK to delete us, we're only a pointer container cliref = NULL; } Netracker::tracked_client *cliref; }; #endif kismet-2013-03-R1b/packetchain.h0000664000175000017500000000627612124602454016111 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETCHAIN_H__ #define __PACKETCHAIN_H__ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include "globalregistry.h" #include "packet.h" // Packet chain progression // GENESIS // --> genesis_chain // // (arbitrary fill-in by whomever generated the packet before injection) // // POST-CAPTURE // // DISSECT // // DECRYPT // // DATA-DISSECT // // CLASSIFIER // // LOGGING // // DESTROY // --> destroy_chain #define CHAINPOS_GENESIS 1 #define CHAINPOS_POSTCAP 2 #define CHAINPOS_LLCDISSECT 3 #define CHAINPOS_DECRYPT 4 #define CHAINPOS_DATADISSECT 5 #define CHAINPOS_CLASSIFIER 6 #define CHAINPOS_LOGGING 7 #define CHAINPOS_DESTROY 8 #define CHAINCALL_PARMS GlobalRegistry *globalreg, void *auxdata, kis_packet *in_pack class Packetchain { public: Packetchain(); Packetchain(GlobalRegistry *in_globalreg); int RegisterPacketComponent(string in_component); int RemovePacketComponent(int in_id); // Generate a packet and hand it back kis_packet *GeneratePacket(); // Inject a packet into the chain int ProcessPacket(kis_packet *in_pack); // Destroy a packet at the end of its life void DestroyPacket(kis_packet *in_pack); // Callback and information typedef int (*pc_callback)(CHAINCALL_PARMS); typedef struct { int priority; Packetchain::pc_callback callback; void *auxdata; } pc_link; // Register a callback, aux data, a chain to put it in, and the priority int RegisterHandler(pc_callback in_cb, void *in_aux, int in_chain, int in_prio); int RemoveHandler(pc_callback in_cb, int in_chain); protected: GlobalRegistry *globalreg; int next_componentid; map component_str_map; map component_id_map; // These two chains get called after a packet is generated and // before the final destruction, respectively vector genesis_chain; vector destruction_chain; // Core chain components vector postcap_chain; vector llcdissect_chain; vector decrypt_chain; vector datadissect_chain; vector classifier_chain; vector logging_chain; }; #endif kismet-2013-03-R1b/gpsfixed.cc0000664000175000017500000000457412124602454015605 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef HAVE_LIBGPS #include "gpsfixed.h" #include "configfile.h" #include "soundcontrol.h" #include "packetchain.h" #include "kismet_json.h" int GpsFixedEvent(Timetracker::timer_event *evt, void *parm, GlobalRegistry *globalreg) { GPSFixed *gps = (GPSFixed *) parm; return gps->Timer(); } GPSFixed::GPSFixed() { fprintf(stderr, "FATAL OOPS: gpsfixed called with no globalreg\n"); exit(-1); } void GPSFixed::ConnectCB(int status) { return; } GPSFixed::GPSFixed(GlobalRegistry *in_globalreg) : GPSCore(in_globalreg) { float tlat, tlon; if (sscanf(globalreg->kismet_config->FetchOpt("gpsposition").c_str(), "%f,%f", &tlat, &tlon) != 2) { _MSG("Invalid gpsposition in config, expected latitude,longitude", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } lat = tlat; lon = tlon; mode = 3; if (sscanf(globalreg->kismet_config->FetchOpt("gpsaltitude").c_str(), "%f", &tlat) != 1) { _MSG("Invalid or missing gpsaltitude=, emulating 2d fix", MSGFLAG_ERROR); mode = 2; } else { alt = tlat; } last_lat = lat; last_lon = lon; gps_ever_lock = 1; gps_connected = 1; gpseventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &GpsFixedEvent, (void *) this); _MSG("Emulating GPS at fixed location " + FloatToString(lat) + "," + FloatToString(lon) + " altitude " + FloatToString(alt), MSGFLAG_INFO); ScanOptions(); RegisterComponents(); } GPSFixed::~GPSFixed() { } int GPSFixed::Shutdown() { return 1; } int GPSFixed::Timer() { GPSCore::Timer(); return 1; } int GPSFixed::Reconnect() { return 1; } int GPSFixed::ParseData() { return 1; } #endif kismet-2013-03-R1b/serialclient.cc0000664000175000017500000000763112124602454016447 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "serialclient.h" SerialClient::SerialClient() { fprintf(stderr, "*** SerialClient() called with no global registry reference\n"); } SerialClient::SerialClient(GlobalRegistry *in_globalreg) : NetworkClient(in_globalreg) { // Nothing special here } SerialClient::~SerialClient() { } int SerialClient::Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux) { (void) in_port; cli_fd = open(in_remotehost, O_RDWR | O_NONBLOCK | O_NOCTTY); if (cli_fd < 0) { int e = errno; _MSG("SerialClient::Connect() failed to open serial device " + string(in_remotehost) + ": " + string(strerror(errno)), MSGFLAG_ERROR); if (in_connect_cb != NULL) (*in_connect_cb)(globalreg, e, in_con_aux); cl_valid = 0; return -1; } cl_valid = 1; read_buf = new RingBuffer(SER_RING_LEN); write_buf = new RingBuffer(SER_RING_LEN); if (in_connect_cb != NULL) (*in_connect_cb)(globalreg, 0, in_con_aux); return 1; } int SerialClient::GetOptions(struct termios *options) { tcgetattr(cli_fd, options); return 1; } int SerialClient::SetOptions(int optmode, struct termios *options) { if (tcsetattr(cli_fd, optmode, options) < 0) { _MSG("SerialClient::SetOptions() failed to set serial device attributes: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } return 1; } int SerialClient::SetBaud(int in_baud) { struct termios options; GetOptions(&options); options.c_oflag = 0; options.c_iflag = 0; cfsetispeed(&options, in_baud); cfsetospeed(&options, in_baud); return SetOptions(TCSANOW, &options); } int SerialClient::FlushSerial(int in_selector) { if (tcflush(cli_fd, in_selector) < 0) { _MSG("SeriaLClient::FlushSerial failed to flush serial queue: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } return 1; } int SerialClient::ReadBytes() { uint8_t recv_bytes[1024]; int ret; if ((ret = read(cli_fd, recv_bytes, 1024)) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, 1024, "Serial client fd %d read() error: %s", cli_fd, strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } return 0; } if (ret == 0) { snprintf(errstr, 1024, "Serial client fd %d socket closed.", cli_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } if (read_buf->InsertData(recv_bytes, ret) == 0) { snprintf(errstr, 1024, "Serial client fd %d read error, ring buffer full", cli_fd); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } return ret; } int SerialClient::WriteBytes() { uint8_t dptr[1024]; int dlen, ret; write_buf->FetchPtr(dptr, 1024, &dlen); if ((ret = write(cli_fd, dptr, dlen)) <= 0) { snprintf(errstr, 1024, "Serial client: Killing client fd %d write error %s", cli_fd, strerror(errno)); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); KillConnection(); return -1; } write_buf->MarkRead(ret); return ret; } kismet-2013-03-R1b/kismap/0000775000175000017500000000000012124602454014737 5ustar dragorndragornkismet-2013-03-R1b/kismap/kismap.py0000775000175000017500000010436312124602454016607 0ustar dragorndragorn#!/usr/bin/python """ Kismet GPS Mapping Rewritten - better, faster, stronger, able to leap tall XML files in a single bound, using modern map repositories. Map repo code ported to python from Maemo Mapper, Copyright (c) 2004-2006 by John Costigan. The algorithm magic is all his. Unless otherwise noted, (c) Mike Kershaw, dragorn@kismetwireless.net GPL v2 """ # Import Psyco if available - why does this only speed up the second time? # meh, whatever try: import psyco psyco.full() except ImportError: print "NOTICE: Psyco not found, things may be slower but it is not required." pass import os, sys, time, xml.sax.handler, getopt, ConfigParser, md5, string from decimal import * from math import * from urllib import urlretrieve try: import gd except ImportError: print "ERROR: Kismap requires gdmodule from:" print " http://newcenturycomputers.net/projects/gdmodule.html" print "(or check your distribution packages)" raise class TileMap: """ Map coordinates onto a tile, and fetch tiles into a cached directory. """ def __init__(self, zoom_mod = 0, url = None, cachedir = None, tiletype = "png"): self.zmod = zoom_mod self.cachedir = cachedir self.url = url self.tiletype = tiletype # Constants from Maemo-Mapper self.MERCATOR_SPAN = (-6.28318377773622) self.MERCATOR_TOP = (3.14159188886811) self.TILE_SIZE_PIXELS = (256) self.TILE_SIZE_P2 = (8) self.MIN_ZOOM = (0) self.MAX_ZOOM = (20) self.WORLD_SIZE_UNITS = (2 << (self.MAX_ZOOM + self.TILE_SIZE_P2)) self.min_xtile = 0 self.min_ytile = 0 self.max_xtile = 0 self.max_ytile = 0 self.zoom = 0 self.px = -1 self.py = -1 def CoordToUnit(self, lat, lon): """ Convert lat,lon to a unit coodinate on the projection """ dlat = float(lat) dlon = float(lon) ux = (dlon + 180.0) * (self.WORLD_SIZE_UNITS / 360.0) + 0.5 tmp = sin(dlat * (pi / 180.0)) uy = 0.50 + (self.WORLD_SIZE_UNITS / self.MERCATOR_SPAN) uy = uy * (log((1.0 + tmp) / (1.0 - tmp)) * 0.50 - self.MERCATOR_TOP); return (int(ux), int(uy)) def UnitToZTile(self, unit, zoom): """ Return the tile that contains a unit """ return ((unit) >> (self.TILE_SIZE_P2 + (zoom + self.zmod))) def TileToZUnit(self, tile, zoom): """ Return the unit coordinates of the top-left of a tile """ return ((tile) << (self.TILE_SIZE_P2 + (zoom + self.zmod))) def UnitToZPixel(self, unit, zoom): """ Return the pixel coordinates of a unit """ return ((unit) >> (zoom + self.zmod)) def TileToPixel(self, tile): """ Return the pixel coordinates of a tile """ return ((tile) << self.TILE_SIZE_P2) def TilesToZURL(self, tx, ty, zoom): if self.url == None: return None urldict = { } urldict["xtile"] = str(tx) urldict["ytile"] = str(ty) urldict["zoom"] = zoom return self.url % urldict def DownloadTileImage(self, tx, ty, zoom, destination): url = self.TilesToZURL(tx, ty, zoom) if url == None: return print "Debug - Downloading", url if (os.access(destination, os.R_OK) == False): urlretrieve(url, destination) else: print "Debug - Not downloading, already cached" def PrepCoords(self, min_lat, min_lon, max_lat, max_lon, zoom): """ Set the coordinates for future prepped ops """ minux, minuy = self.CoordToUnit(min_lat, min_lon) maxux, maxuy = self.CoordToUnit(max_lat, max_lon) self.min_xtile = self.UnitToZTile(minux, zoom) self.min_ytile = self.UnitToZTile(minuy, zoom) self.max_xtile = self.UnitToZTile(maxux, zoom) self.max_ytile = self.UnitToZTile(maxuy, zoom) if (self.max_xtile < self.min_xtile): mx = self.min_xtile self.min_xtile = self.max_xtile self.max_xtile = mx if (self.max_ytile < self.min_ytile): my = self.min_ytile self.min_ytile = self.max_ytile self.max_ytile = my self.zoom = zoom self.min_xtile = self.min_xtile - 1 self.min_ytile = self.min_ytile - 1 self.max_xtile = self.max_xtile + 1 self.max_ytile = self.max_ytile + 1 print self.min_xtile, self.min_ytile, self.max_xtile, self.max_ytile def FetchTileCount(self): """ Total # of tiles we'll download after prepping coords """ xrange = self.max_xtile - self.min_xtile yrange = self.max_ytile - self.min_ytile if (xrange == 0): xrange = 1 if (yrange == 0): yrange = 1 return xrange * yrange def DownloadTiles(self): for x in range(self.min_xtile, self.max_xtile): # Cache in cache/zoom/coord/y.png cachedir = self.cachedir + "/" + str(self.zoom) + "/" + str(x) if (os.access(cachedir, os.W_OK) == False): os.makedirs(cachedir) for y in range(self.min_ytile, self.max_ytile): cachefile = cachedir + "/" + str(y) + "." + self.tiletype self.DownloadTileImage(x, y, self.zoom, cachefile) def FetchStitchedImage(self): """ Return a stitched image of all the points """ self.DownloadTiles() xrange = self.max_xtile - self.min_xtile yrange = self.max_ytile - self.min_ytile if (xrange == 0): xrange = 1 if (yrange == 0): yrange = 1 imgw = xrange * self.TILE_SIZE_PIXELS imgh = yrange * self.TILE_SIZE_PIXELS print "Allocating image ", imgw, "x", imgh img = gd.image((imgw, imgh), 1) if self.url != None: for x in range(self.min_xtile, self.max_xtile): for y in range(self.min_ytile, self.max_ytile): tileimg = gd.image(self.cachedir + "/" + str(self.zoom) + "/" + str(x) + "/" + str(y) + "." + self.tiletype) xpos = (x - self.min_xtile) * self.TILE_SIZE_PIXELS ypos = (y - self.min_ytile) * self.TILE_SIZE_PIXELS tileimg.copyTo(img, (xpos, ypos)) else: rectclr = img.colorAllocate((255, 255, 255)) img.rectangle((0, 0), (imgw, imgh), rectclr, rectclr) return img def CoordToPrepPixel(self, lat, lon): spux = self.TileToZUnit(self.min_xtile, self.zoom) spuy = self.TileToZUnit(self.min_ytile, self.zoom) sppx = self.UnitToZPixel(spux, self.zoom) sppy = self.UnitToZPixel(spuy, self.zoom) ux, uy = self.CoordToUnit(lat, lon) upx = self.UnitToZPixel(ux, self.zoom) upy = self.UnitToZPixel(uy, self.zoom) return ((upx - sppx), (upy - sppy)) class GpsPoint: """ Representation of a GPS point from the gpsxml file Uses math.decimal to prevent float manipulation errors in lat/lon over massive averaging, etc """ def __init__(self, xml = None, txt = None): if xml != None: try: self.bssid = xml["bssid"] self.source = xml["source"] self.timesec = int(xml["time-sec"]) self.timeusec = int(xml["time-usec"]) self.lat = Decimal(xml["lat"]) self.lon = Decimal(xml["lon"]) self.alt = Decimal(xml["alt"]) self.spd = Decimal(xml["spd"]) self.heading = Decimal(xml["heading"]) self.fix = int(xml["fix"]) self.signal = int(xml["signal"]) self.noise = int(xml["noise"]) except: raise elif txt != None: try: ta = string.split(txt, "\001") self.bssid = ta[0] self.source = ta[1] self.timesec = int(ta[2]) self.timeusec = int(ta[3]) self.lat = Decimal(ta[4]) self.lon = Decimal(ta[5]) self.alt = Decimal(ta[6]) self.spd = Decimal(ta[7]) self.heading = Decimal(ta[8]) self.fix = int(ta[9]) self.signal = int(ta[10]) self.noise = int(ta[11]) except: raise else: self.bssid = "" self.source = "" self.timesec = 0 self.timeusec = 0 self.lat = Decimal(0) self.lon = Decimal(0) self.alt = Decimal(0) self.spd = Decimal(0) self.heading = Decimal(0) self.fix = 0 self.signal = 0 self.noise = 0 self.zpx = 0 self.zpy = 0 self.avgcenter_px = -1 self.avgcenter_py = -1 def Cache(self): r = [] r.append(self.bssid) r.append(self.source) r.append(str(self.timesec)) r.append(str(self.timeusec)) r.append(str(self.lat)) r.append(str(self.lon)) r.append(str(self.alt)) r.append(str(self.spd)) r.append(str(self.heading)) r.append(str(self.fix)) r.append(str(self.signal)) r.append(str(self.noise)) return "\001".join(r) class GpsNetwork: """ Representation of a network from netxml Less than a Kismet network definition and not a full representation of the data kept in the netxml record, because we don't need it """ def __init__(self, xml = None): self.points = [] self.min_lat = Decimal("90") self.min_lon = Decimal("180") self.max_lat = Decimal("-90") self.max_lon = Decimal("-180") self.avgcenter_px = -1 self.avgcenter_py = -1 self.clients = { } self.sorted = 0 self.sorted_points = [] self.sorted_min_lat = Decimal("90") self.sorted_min_lon = Decimal("180") self.sorted_max_lat = Decimal("-90") self.sorted_max_lon = Decimal("-180") self.sorted_avgcenter_px = -1 self.sorted_avgcenter_py = -1 if xml == None: self.ssid = [] self.bssid = "" self.channel = 0 self.maxrate = float(0) self.carrier = "" self.encryption = "" self.type = "" self.cloaked = 0 class GpsClient: """ Limited representation of a network client """ def __init__(self, xml = None): self.source = "" self.points = [] self.min_lat = Decimal("90") self.min_lon = Decimal("180") self.max_lat = Decimal("-90") self.max_lon = Decimal("-180") self.avgcenter_px = -1 self.avgcenter_py = -1 def sort_pt_alg_lat(x, y): if x.lat < y.lat: return -1 elif x.lat == y.lat: return 0 else: return 1 def sort_pt_alg_lon(x, y): if x.lon < y.lon: return -1 elif x.lon == y.lon: return 0 else: return 1 def sort_pt_alg_time(x, y): if x.timesec < y.timesec: return -1 elif x.timesec == y.timesec: if x.timeusec < y.timeusec: return -1 elif x.timeusec == y.timeusec: return 0 else: return 1 else: return 1 class KismetStblGpsHandler(xml.sax.handler.ContentHandler): """ XML handlers for kismet-stable gpsxml files """ def __init__(self): self.networks = { } self.gpspoints = [] self.start_time = 0 self.in_run = 0 self.in_netfile = 0 self.netfile = "" self.filtered = 0 def NumPoints(self): return len(self.gpspoints) def startElement(self, name, attributes): if (name == "network-file"): self.in_netfile = 1 elif (name == "gps-point"): try: gp = GpsPoint(attributes) self.gpspoints.append(gp) except: print "Error on GPS point" def characters(self, data): if (self.in_netfile): self.netfile = data def endelement(self, name): if (name == "network-file" and self.in_netfile): self.in_netfile = 0 def FetchPoints(self): return self.gpspoints def LoadCache(self, fname): try: cf = open(fname, 'r') except: print "INFO: Couldn't open cache file", fname return 0 print "INFO: Loading from cache file", fname try: self.start_time = int(cf.readline()) except: print "ERROR: Invalid start time in cache", fname return 0 try: self.netfile = cf.readline()[:-1] except: print "ERROR: Invalid netfile in cache", fname return 0 for g in cf.readlines(): try: gp = GpsPoint(txt = g) except: print "ERROR: Invalid gps point in cache", fname return len(self.gpspoints) self.gpspoints.append(gp) cf.close() self.filtered = 1 return 1 def SaveCache(self, fname): try: cf = open(fname, 'w') except: print "INFO: Couldn't open cache file", fname, "for writing" return 0 cf.write("%s\n" % self.start_time) cf.write("%s\n" % self.netfile) for g in self.gpspoints: cf.write("%s\n" % g.Cache()) cf.close() return 1 class KismetStblNetHandler(xml.sax.handler.ContentHandler): """ XML handlers for kismet-stable gpsxml files """ def __init__(self): self.networks = { } self.clients = { } self.gpspoints = [] self.start_time = 0 self.in_run = 0 self.in_netfile = 0 self.netfile = "" def NumPoints(self): return len(self.gpspoints) def startElement(self, name, attributes): if (name == "network-file"): self.in_netfile = 1 elif (name == "gps-point"): gp = GpsPoint(attributes) self.gpspoints.append(gp) def characters(self, data): if (self.in_netfile): self.netfile = data def endelement(self, name): if (name == "network-file" and self.in_netfile): self.in_netfile = 0 def FetchPoints(self): return self.gpspoints class GpsAggregate: """ Aggregate GPS data of multiple points, what gets plotted out to file """ def __init__(self, verbose = 0): self.networks = { } self.tracks = [] self.min_lat = Decimal("90") self.min_lon = Decimal("180") self.max_lat = Decimal("-90") self.max_lon = Decimal("-180") self.num = 0 self.image = None self.tilemapper = None self.verbose = verbose def AddMapper(self, image, tilemapper): self.image = image self.tilemapper = tilemapper def AddGpsXML(self, xmlhandler): points = xmlhandler.FetchPoints() if xmlhandler.filtered == 0: if self.verbose: print "Filtering points..." self.FilterPoints(points) self.tracks.append([]) for i in range(0, len(points)): # Throw out bogus points that still have a "valid" fix if points[i].lat == 0 and points[i].lon == 0 and points[i].alt == 0: continue # Add it to the track list if (points[i].bssid == "GP:SD:TR:AC:KL:OG"): self.tracks[self.num].append(points[i]) else: curnet = None if (self.networks.has_key(points[i].bssid)): curnet = self.networks[points[i].bssid] else: curnet = GpsNetwork() curnet.bssid = points[i].bssid self.networks[points[i].bssid] = curnet curnet.points.append(points[i]) if (points[i].bssid != points[i].source): curcli = None if curnet.clients.has_key(points[i].source): curcli = curnet.clients[points[i].source] else: curcli = GpsClient() curcli.source = points[i].source curnet.clients[points[i].source] = curcli curcli.points.append(points[i]) # Combine it with the bounds if (points[i].lat < self.min_lat): self.min_lat = points[i].lat if (points[i].lon < self.min_lon): self.min_lon = points[i].lon if (points[i].lat > self.max_lat): self.max_lat = points[i].lat if (points[i].lon > self.max_lon): self.max_lon = points[i].lon self.num = self.num + 1 def FilterPoints(self, pointlist, threshold = Decimal("0.5")): """ Filter out junk data points caused by GPS noise or other nonsense that got into the data. Filter by sorting and looking for gaps greater than the threshold value: this seems to be a fairly accurate and relatively quick way to sort out the bunk points, and far better than trying to walk the path and look for outliers * Sort by (lat|lon) * Walk lower half (incrementing) * Get trim value * Walk upper half (decrementing) * Get trim value * Trim """ lower_slice_point = -1 upper_slice_point = -1 pointlist.sort(sort_pt_alg_lon) for i in range(1, len(pointlist) / 2): offt = abs(pointlist[i].lon - pointlist[i - 1].lon) if (offt > threshold): lower_slice_point = i for i in range(len(pointlist) - 1, len(pointlist) / 2, -1): offt = abs(pointlist[i].lon - pointlist[i - 1].lon) if (offt > threshold): upper_slice_point = i if (lower_slice_point > 0 or upper_slice_point > 0): if (lower_slice_point < 0): lower_slice_point = 0 if (upper_slice_point > len(pointlist)): upper_slice_point = len(pointlist) pointlist = pointlist[lower_slice_point:upper_slice_point] lower_slice_point = -1 upper_slice_point = -1 pointlist.sort(sort_pt_alg_lat) for i in range(1, len(pointlist) / 2): offt = abs(pointlist[i].lat - pointlist[i - 1].lat) if (offt > threshold): lower_slice_point = i for i in range(len(pointlist) - 1, len(pointlist) / 2, -1): offt = abs(pointlist[i].lat - pointlist[i - 1].lat) if (offt > threshold): upper_slice_point = i if (lower_slice_point > 0 or upper_slice_point > 0): if (lower_slice_point < 0): lower_slice_point = 0 if (upper_slice_point > len(pointlist)): upper_slice_point = len(pointlist) pointlist = pointlist[lower_slice_point:upper_slice_point] pointlist.sort(sort_pt_alg_time) return pointlist def ProcessNetworkdata(self): """ Process network points and get centers, etc Call after all networks are added and dispersed through the aggregation. """ for k in self.networks.keys(): curnet = self.networks[k] avgpx = 0 avgpy = 0 avgc = 0 lastlat = 0 lastlon = 0 for p in curnet.points: """ Cache the pixel-zoom location """ p.px, p.py = self.tilemapper.CoordToPrepPixel(p.lat, p.lon) if (p.lat < curnet.min_lat): curnet.min_lat = p.lat if (p.lon < curnet.min_lon): curnet.min_lon = p.lon if (p.lat > curnet.max_lat): curnet.max_lat = p.lat if (p.lon > curnet.max_lon): curnet.max_lon = p.lon """ Average the network center based on integer math to avoid floating point rounding nonsense """ if not lastlat == p.lat or not lastlon == p.lon: lastlat = p.lat lastlon = p.lon avgpx = avgpx + p.px avgpy = avgpy + p.py avgc = avgc + 1 curnet.avgcenter_px = int(avgpx / avgc) curnet.avgcenter_py = int(avgpy / avgc) curnet.sorted_points = self.FilterPoints(curnet.points, Decimal("0.0005")) avgpx = 0 avgpy = 0 avgc = 0 lastlat = 0 lastlon = 0 for p in curnet.sorted_points: # Don't use clients in the network sorting, only beacons (or at # least, only traffic FROM the AP) to prevent severe distortion # from spurious outliers if not p.source == p.bssid: continue if (p.lat < curnet.sorted_min_lat): curnet.sorted_min_lat = p.lat if (p.lon < curnet.sorted_min_lon): curnet.sorted_min_lon = p.lon if (p.lat > curnet.sorted_max_lat): curnet.sorted_max_lat = p.lat if (p.lon > curnet.sorted_max_lon): curnet.sorted_max_lon = p.lon if not lastlat == p.lat or not lastlon == p.lon: lastlat = p.lat lastlon = p.lon avgpx = avgpx + p.px avgpy = avgpy + p.py avgc = avgc + 1 if not avgc == 0: curnet.sorted_avgcenter_px = int(avgpx / avgc) curnet.sorted_avgcenter_py = int(avgpy / avgc) curnet.sorted = 1 """ Average the client locations """ for c in curnet.clients.values(): avgpx = 0 avgpy = 0 avgc = 0 lastlat = 0 lastlon = 0 for p in c.points: if not lastlat == p.lat or not lastlon == p.lon: lastlat = p.lat lastlon = p.lon avgpx = avgpx + p.px avgpy = avgpy + p.py avgc = avgc + 1 c.avgcenter_px = int(avgpx / avgc) c.avgcenter_py = int(avgpy / avgc) for t in self.tracks: for p in t: p.px, p.py = self.tilemapper.CoordToPrepPixel(p.lat, p.lon) def DrawTracks(self, rgb, trackwidth, simplify = 1, rgbmod = (0, 0, 10)): """ Draw tracks """ for t in self.tracks: trackclr = self.image.colorAllocate(rgb) self.image.setThickness(trackwidth) for p in range(0, len(t) - simplify, simplify): ex = t[p + simplify].px ey = t[p + simplify].py self.image.line((t[p].px, t[p].py), (ex, ey), trackclr) def DrawNetCenters(self, rgb, diameter): """ Draw network center points w/ raw averaging of the center. Use converted pixel coordinates of points to minimize float errors which happen when we use lat/lon """ netclr = self.image.colorAllocate(rgb) self.image.setThickness(3) for n in self.networks.values(): if n.sorted_avgcenter_py < 0 or n.sorted_avgcenter_px < 0: continue cpx = n.sorted_avgcenter_px - (diameter / 2) cpy = n.sorted_avgcenter_py - (diameter / 2) self.image.filledArc((cpx, cpy), (diameter, diameter), 0, 360, netclr, 4) def DrawClientLinks(self, rgb, diameter, lines = 1): netclr = self.image.colorAllocate(rgb) self.image.setThickness(1) for n in self.networks.values(): if n.sorted_avgcenter_py < 0 or n.sorted_avgcenter_px < 0: continue npx = n.sorted_avgcenter_px npy = n.sorted_avgcenter_py for c in n.clients.values(): if c.avgcenter_py < 0 or c.avgcenter_px < 0: continue cpx = c.avgcenter_px - (diameter / 2) cpy = c.avgcenter_py - (diameter / 2) self.image.filledArc((cpx, cpy), (diameter, diameter), 0, 360, netclr, 0) if lines: self.image.line((c.avgcenter_px, c.avgcenter_py), (npx, npy), netclr) def DrawNetRects(self, rgb, linewidth): rectclr = self.image.colorAllocate(rgb) self.image.setThickness(linewidth) for n in self.networks.values(): sx, sy = self.tilemapper.CoordToPrepPixel(n.min_lat, n.min_lon) ex, ey = self.tilemapper.CoordToPrepPixel(n.max_lat, n.max_lon) if ex < sx: tx = sx sx = ex ex = tx if ey < sy: ty = sy sy = ey ey = ty if ex - sx > 50: print "debug -", n.max_lat - n.min_lat, n.max_lon - n.min_lon self.image.rectangle((sx, sy), (ex, ey), rectclr) def DrawNetRangeCircs(self, rgba): circclr = self.image.colorAllocateAlpha(rgba) self.image.setThickness(1) for n in self.networks.values(): if n.sorted_avgcenter_py < 0 or n.sorted_avgcenter_px < 0: continue sx, sy = self.tilemapper.CoordToPrepPixel(n.sorted_min_lat, n.sorted_min_lon) ex, ey = self.tilemapper.CoordToPrepPixel(n.sorted_max_lat, n.sorted_max_lon) if ex < sx: tx = sx sx = ex ex = tx if ey < sy: ty = sy sy = ey ey = ty diagonal = sqrt(((ex-sx)*(ex-sx)) + (((ey-sy)*(ey-sy)))) cpx = sx + ((ex - sx) / 2) cpy = sy + ((ey - sy) / 2) self.image.filledArc((cpx, cpy), (diagonal, diagonal), 0, 360, circclr, 0) def DrawNetHull(self): hullclr = self.image.colorAllocate((255, 0, 0, 50)) def help(): print "%s [opts] [gpsxml files]" % sys.argv[0] print " -v/--verbose Verbose output" print " -o/--output-image Image to write" print " -z/--zoom Zoom level" print " -C/--config Alternate config file" print " -c/--center Center of map (lat,lon)" print " -r/--radius Radius (in miles) to plot around center" def BoundingSquare(lat, lon, r): rlat = (lat * pi) / 180 rlon = (lon * pi) / 180 # Earth in KM R = 6371 d = float(r)/R a = 0 tlat = asin(sin(rlat) * cos(d) + cos(rlat) * sin(d) * cos(a)) tlon = ((rlon + atan2(sin(a) * sin(d) * cos(rlat), cos(d) - sin(rlat) * sin(tlat))) * 180) / pi tlat = (tlat * 180) / pi maxlat = tlat a = 270 * pi / 180 tlat = asin(sin(rlat) * cos(d) + cos(rlat) * sin(d) * cos(a)) tlon = ((rlon + atan2(sin(a) * sin(d) * cos(rlat), cos(d) - sin(rlat) * sin(tlat))) * 180) / pi tlat = (tlat * 180) / pi maxlon = tlon a = 90 tlat = asin(sin(rlat) * cos(d) + cos(rlat) * sin(d) * cos(a)) tlon = ((rlon + atan2(sin(a) * sin(d) * cos(rlat), cos(d) - sin(rlat) * sin(tlat))) * 180) / pi tlat = (tlat * 180) / pi minlon = tlon a = 180 tlat = asin(sin(rlat) * cos(d) + cos(rlat) * sin(d) * cos(a)) tlon = ((rlon + atan2(sin(a) * sin(d) * cos(rlat), cos(d) - sin(rlat) * sin(tlat))) * 180) / pi tlat = (tlat * 180) / pi minlat = tlat return (minlat, minlon, maxlat, maxlon) def main(): try: opts, args = getopt.getopt(sys.argv[1:], "hvz:o:C:c:r:", ["help", "verbose", "zoom", "output-image", "config", "center", "radius"]) except getopt.error, msg: print msg print "For help, %s --help" % sys.argv[0] sys.exit(2) conf_main = { "name": "KisMap", "mapsource": "blank", "cachemaps": "true", "zoom": "3", "filename": "kismap.png", "cachexml": "true", "cachedir": ".", "map-center": "", "map-radius": "" } conf_drawing = { "tracks": "true", "powermap": "false", "bounds": "false", "range": "true", "hull": "false", "scatter": "false", "center": "true", "netlabels": "false", "clientlabels": "false", "legend": "true" } conf_map = { "url": None, "zoomadjust": "4" } xml.sax.handler.feature_external_ges = 0 xml.sax.handler.feature_external_pes = 0 verbose = 0 cfvalid = 0 #confdir = os.path.expanduser("~/.kismet") confdir = "." conffile = os.path.join(confdir, "kismap.conf") cfparser = ConfigParser.SafeConfigParser() # Parse just the config option for o, a in opts: if o in ("-C", "--config"): conffile = a cf = None print "debug - looking at conf file %s" % conffile try: cf = open(conffile, "r") except: print "Failed to open config file %s" % conffile raise try: cfparser.readfp(cf) cfvalid = 1 except: print "Failed to parse config file %s" % conffile raise if cfvalid: conf_main.update(cfparser.items("main")) conf_drawing.update(cfparser.items("drawing")) conf_map.update(cfparser.items("map_%s" % conf_main["mapsource"])) try: confdir = os.path.expanduser(conf_main["cachedir"]) conf_main["cachedir"] = confdir except: print "ERROR: No 'confdir' in Main section" raise try: conf_main["zoom"] = int(conf_main["zoom"]) except: print "ERROR: Main::Zoom must be an integer" raise try: conf_map["zoomadjust"] = int(conf_map["zoomadjust"]) except: print "ERROR: Map::Zoomadjust must be an integer" raise for o, a in opts: if o in ("-h", "--help"): help() sys.exit(0) elif o in ("-v", "--verbose"): verbose = 1 elif o in ("-z", "--zoom"): try: conf_main["zoom"] = int(a) except: print "Zoom must be an integer" sys.exit(2) elif o in ("-o", "--output-image"): conf_main["filename"] = a elif o in ("-c", "--center"): conf_main["map-center"] = a elif o in ("-r", "--radius"): conf_main["map-radius"] = a if len(args) == 0: print "Specify at least one XML file" sys.exit(2) # Set math.decimal context up DefaultContext.prec = 6 DefaultContext.rounding = ROUND_DOWN DefaultContext.traps = ExtendedContext.traps.copy() DefaultContext.traps[InvalidOperation] = 1 setcontext(DefaultContext) agg = GpsAggregate(verbose = verbose) if (os.access(confdir, os.W_OK) == False): os.makedirs(confdir) for f in args: cached = 0 cfname = "" parser = xml.sax.make_parser() handler = KismetStblGpsHandler() parser.setContentHandler(handler) if verbose: print "Processing XML file", f if conf_main["cachexml"] == "true": try: xf = open(f, 'r') except: print "ERROR: Could not open", f, " for reading" raise m = md5.new() m.update(xf.read()) xf.close() cfname = os.path.join(conf_main["cachedir"], "xmlcache") if (os.access(cfname, os.W_OK) == False): os.makedirs(cfname) cfname = os.path.join(cfname, m.hexdigest()) if handler.LoadCache(cfname): cached = 1 if cached == 0: try: parser.parse(f) except xml.sax._exceptions.SAXParseException: print "*** XML parser failed, atempting to use what we've got" if verbose: print "Number of points parsed, ", handler.NumPoints() if handler.NumPoints() > 0: agg.AddGpsXML(handler) if conf_main["cachexml"] == "true" and cached == 0: handler.SaveCache(cfname) if verbose: print "Map %f,%f by %f,%f" % (agg.min_lat, agg.min_lon, agg.max_lat, agg.max_lon) # Set up the tilemap handler tilecache = os.path.join(confdir, "%s-cache" % conf_main["mapsource"]) if verbose: print "Caching tiles in", tilecache tm = TileMap(conf_map["zoomadjust"], url = conf_map["url"], cachedir = tilecache) if verbose: print "Using zoom", conf_main["zoom"] if (conf_main["map-center"] == ""): tm.PrepCoords(agg.min_lat, agg.min_lon, agg.max_lat, agg.max_lon, conf_main["zoom"]) else: try: (slat,slon) = string.split(conf_main["map-center"], ",") clat = float(slat) clon = float(slon) except: print "Invalid map center, expected lat,lon" raise (minlat,minlon,maxlat,maxlon) = BoundingSquare(clat, clon, float(conf_main["map-radius"])) tm.PrepCoords(minlat, minlon, maxlat, maxlon, conf_main["zoom"]) if verbose: print "Needs", tm.FetchTileCount(), "tiles" img = tm.FetchStitchedImage() agg.AddMapper(img, tm) if verbose: print "Processing network data" agg.ProcessNetworkdata() if not conf_drawing["tracks"] == "false": if verbose: print "Drawing tracks" agg.DrawTracks((0, 0, 255), 8, simplify = 10) if not conf_drawing["bounds"] == "false": if verbose: print "Network rects" agg.DrawNetRects((0, 255, 0), 3) if not conf_drawing["range"] == "false": if verbose: print "Network range" agg.DrawNetRangeCircs((0, 255, 255, 96)) if not conf_drawing["center"] == "false": if verbose: print "Network centers" agg.DrawNetCenters((255, 0, 255), 8) if not conf_drawing["clients"] == "false": if verbose: print "Client positions" agg.DrawClientLinks((0, 255, 0), 5) if verbose: print "Saving stitched image", conf_main["filename"] img.writePng(conf_main["filename"]) main() kismet-2013-03-R1b/kismap/kismap.conf0000664000175000017500000000356012124602454017076 0ustar dragorndragorn# Kismap configuration [main] # config and cache directory cachedir = ~/.kismet/ # Name used in the legend name = KisMap # Map source we use mapsource = google # Cache parsed point data cachexml = true # Default zoom level zoom = 3 # Default filename filename = kismap.png # Main drawing elements - What gets draw, and what order it gets drawn # in. These can also be controlled from the command line. [drawing] # Plot tracks (travel paths) tracks = true # Plot powermap (weathermap style interpolated power) powermap = false # Plot network bounds rectangles bounds = false # Plot circular estimated network ranges range = true # Convex hull hull = false # Scatterplot of all sensed points scatter = false # Network center center = true # Network client position and links clients = true # Network labels netlabels = false # Client labels clientlabels = false # Legend legend = true # Plotting order # Order in which enabled options are drawn. Does not imply that # all options listen in the order will be drawn, but if you want to # change how things are layered, this is where you'd do it. draworder = powermap,tracks,bounds,range,hull,scatter,center,client,labels [map_blank] # Example map source which does nothing [map_google] # USING A COMMERCIAL MAP SOURCE WITH THE TOOL MAY VIOLATE THE # TERMS OF SERVICE OF THE MAP PROVIDER. # # THESE MAP SOURCES ARE PROVIDED AS EXAMPLES ONLY. # # THE AUTHOR(S) ARE NOT RESPONSIBLE FOR THE USE OF THESE MAP # DEFINITIONS WITHOUT THE PERMISSION OF THE MAP SERVICE. # Map source URLs are encoded as python dictionary strings where: # %%(xtile)s = X coordinate tile # %%(ytile)s = Y coordinate tile # %%(zoom)s = Zoom number # %%(quad)s = Quadtree enumerated tile coordinate # Vector (ie, drawn) map source URL url = http://mt.google.com/mt?x=%%(xtile)s&y=%%(ytile)s&zoom=%%(zoom)s # Zoom factor (if source doesn't map 1:1) zoomadjust = 4 kismet-2013-03-R1b/kismap/README0000664000175000017500000000007712124602454015623 0ustar dragorndragornIncomplete. Don't bug me if it doesn't work! (And it won't!) kismet-2013-03-R1b/kis_panel_preferences.cc0000664000175000017500000014427012124602454020320 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include #include #include #include #include #include #include "kis_panel_widgets.h" #include "kis_panel_frontend.h" #include "kis_panel_windows.h" #include "kis_panel_preferences.h" #include "soundcontrol.h" const char *coloransi[] = { "white", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "hi-black", "hi-red", "hi-green", "hi-yellow", "hi-blue", "hi-magenta", "hi-cyan", "hi-white" }; const char *colortext[] = { "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White", "Grey", "Hi-Red", "Hi-Green", "Hi-Yellow", "Hi-Blue", "Hi-Magenta", "Hi-Cyan", "Hi-White" }; Kis_ColorPref_Component::Kis_ColorPref_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { active = 0; for (int x = 0; x < 16; x++) { colors[x] = parent_panel->AddColor(coloransi[x]); } cpos = 0; text_color = 0; SetPreferredSize(32, 2); } Kis_ColorPref_Component::~Kis_ColorPref_Component() { } void Kis_ColorPref_Component::Activate(int sub) { active = 1; } void Kis_ColorPref_Component::Deactivate() { active = 0; } void Kis_ColorPref_Component::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(text_color, "text_color"); wattrset(window, text_color); if (active) mvwaddch(window, sy, sx, '>'); int hpos = 2; for (int x = 0; x < 16; x++) { hpos++; wattrset(window, text_color); if (x == cpos) { mvwaddch(window, sy, sx + hpos, '['); hpos++; } wattrset(window, colors[x]); mvwaddch(window, sy, sx + hpos, 'X'); hpos++; wattrset(window, text_color); if (x == cpos) { mvwaddch(window, sy, sx + hpos, ']'); hpos++; } } wattrset(window, text_color); mvwaddstr(window, sy, sx + hpos + 1, colortext[cpos]); } int Kis_ColorPref_Component::KeyPress(int in_key) { if (visible == 0) return 0; if (in_key == KEY_RIGHT) { cpos++; if (cpos >= 16) cpos = 0; return cpos + 1; } if (in_key == KEY_LEFT) { cpos--; if (cpos < 0) cpos = 15; return cpos + 1; } return 0; } void Kis_ColorPref_Component::SetColor(string in_color) { string s = StrLower(in_color); for (unsigned int x = 0; x < 16; x++) { if (s == StrLower(colortext[x])) { cpos = x; return; } } } string Kis_ColorPref_Component::GetColor() { if (cpos < 0 || cpos >= 16) return "black"; return string(colortext[cpos]); } int ColorprefButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ColorPref_Picker *) aux)->ButtonAction(component); return 1; } Kis_ColorPref_Picker::Kis_ColorPref_Picker(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { fgcolor = new Kis_ColorPref_Component(globalreg, this); bgcolor = new Kis_ColorPref_Component(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColorprefButtonCB, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColorprefButtonCB, this); AddComponentVec(fgcolor, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(bgcolor, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); tab_pos = 0; active_component = fgcolor; fgcolor->Activate(1); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); hbox = new Kis_Panel_Packbox(globalreg, this); hbox->SetPackH(); hbox->SetHomogenous(1); hbox->SetSpacing(1); hbox->SetCenter(1); hbox->Show(); hbox->Pack_End(cancelbutton, 0, 0); hbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(fgcolor, 0, 0); vbox->Pack_End(bgcolor, 0, 0); vbox->Pack_End(hbox, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); okbutton->SetText("Save"); cancelbutton->SetText("Cancel"); fgcolor->Show(); bgcolor->Show(); okbutton->Show(); cancelbutton->Show(); text_color = 0; } Kis_ColorPref_Picker::~Kis_ColorPref_Picker() { } void Kis_ColorPref_Picker::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); vbox->SetPosition(1, 2, in_x - 2, in_y - 3); } void Kis_ColorPref_Picker::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); wattrset(win, text_color); mvwaddstr(win, 1, 5, "Foregound:"); mvwaddstr(win, 3, 5, "Background:"); for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_DRAW) == 0) continue; pan_comp_vec[x].comp->DrawComponent(); } wmove(win, 0, 0); } void Kis_ColorPref_Picker::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { kpinterface->prefs->SetOpt(prefname, fgcolor->GetColor() + "," + bgcolor->GetColor(), time(0)); globalreg->panel_interface->KillPanel(this); return; } if (in_button == cancelbutton) { globalreg->panel_interface->KillPanel(this); return; } } void Kis_ColorPref_Picker::LinkColorPref(string in_prefname) { prefname = in_prefname; vector sv = StrTokenize(kpinterface->prefs->FetchOpt(prefname), ","); if (sv.size() >= 1) fgcolor->SetColor(sv[0]); if (sv.size() >= 2) bgcolor->SetColor(sv[1]); } int ColorPrefCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ColorPref_Panel *) aux)->SelectedAction(component, status); return 1; } Kis_ColorPref_Panel::Kis_ColorPref_Panel(GlobalRegistry *in_globalref, KisPanelInterface *in_intf) : Kis_Panel(in_globalref, in_intf) { colorlist = new Kis_Scrollable_Table(globalreg, this); colorlist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColorPrefCB, this); AddComponentVec(colorlist, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); vector titles; Kis_Scrollable_Table::title_data t; t.width = 20; t.title = "Color"; t.alignment = 0; titles.push_back(t); t.width = 20; t.title = "Value"; t.alignment = 0; titles.push_back(t); colorlist->AddTitles(titles); colorlist->Show(); closebutton = new Kis_Button(globalreg, this); closebutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColorPrefCB, this); closebutton->SetText("Close"); closebutton->Show(); AddComponentVec(closebutton, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(colorlist, 1, 0); vbox->Pack_End(closebutton, 0, 0); active_component = colorlist; tab_pos = 0; colorlist->Activate(0); main_component = vbox; Position(WIN_CENTER(20, 50)); } Kis_ColorPref_Panel::~Kis_ColorPref_Panel() { } void Kis_ColorPref_Panel::DrawPanel() { vector td; for (unsigned int x = 0; x < listedcolors.size(); x++) { td.clear(); td.push_back(listedcolors[x].text); td.push_back(StrLower(kpinterface->prefs->FetchOpt(listedcolors[x].pref))); colorlist->ReplaceRow(x, td); } Kis_Panel::DrawPanel(); } void Kis_ColorPref_Panel::SelectedAction(Kis_Panel_Component *component, int listkey) { if (component == colorlist) { if (listkey >= 0 && listkey <= (int) listedcolors.size()) { Kis_ColorPref_Picker *cp = new Kis_ColorPref_Picker(globalreg, kpinterface); cp->LinkColorPref(listedcolors[listkey].pref); cp->Position((LINES / 2) - 4, (COLS / 2) - 25, 10, 50); kpinterface->AddPanel(cp); } } else if (component == closebutton) { globalreg->panel_interface->KillPanel(this); return; } return; } void Kis_ColorPref_Panel::AddColorPref(string pref, string name) { cprefpair cpp; cpp.text = name; cpp.pref = pref; listedcolors.push_back(cpp); } int AutoconprefButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AutoConPref_Panel *) aux)->ButtonAction(component); return 1; } Kis_AutoConPref_Panel::Kis_AutoConPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { hostname = new Kis_Single_Input(globalreg, this); hostport = new Kis_Single_Input(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); autoconcheck = new Kis_Checkbox(globalreg, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AutoconprefButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AutoconprefButtonCB, this); AddComponentVec(hostname, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(hostport, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(autoconcheck, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); tab_pos = 0; active_component = hostname; hostname->Activate(1); SetTitle("Connect to Server"); hostname->SetLabel("Host", LABEL_POS_LEFT); hostname->SetTextLen(120); hostname->SetCharFilter(FILTER_ALPHANUMSYM); hostname->SetText(kpinterface->prefs->FetchOpt("default_host"), -1, -1); hostport->SetLabel("Port", LABEL_POS_LEFT); hostport->SetTextLen(5); hostport->SetCharFilter(FILTER_NUM); hostport->SetText(kpinterface->prefs->FetchOpt("default_port"), -1, -1); autoconcheck->SetText("Auto-connect"); // autoconcheck->SetChecked(kpinterface->prefs->FetchOpt("autoconnect") == "true"); autoconcheck->SetChecked(kpinterface->prefs->FetchOptBoolean("autoconnect", 0)); okbutton->SetText("Save"); cancelbutton->SetText("Cancel"); hostname->Show(); hostport->Show(); autoconcheck->Show(); okbutton->Show(); cancelbutton->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(hostname, 0, 0); vbox->Pack_End(hostport, 0, 0); vbox->Pack_End(autoconcheck, 0, 0); vbox->Pack_End(bbox, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); active_component = hostname; hostname->Activate(1); main_component = vbox; Position(WIN_CENTER(11, 40)); } Kis_AutoConPref_Panel::~Kis_AutoConPref_Panel() { } void Kis_AutoConPref_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); vbox->SetPosition(1, 2, in_x - 2, in_y - 3); } void Kis_AutoConPref_Panel::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); wattrset(win, text_color); for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_DRAW) == 0) continue; pan_comp_vec[x].comp->DrawComponent(); } wmove(win, 0, 0); } void Kis_AutoConPref_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { kpinterface->prefs->SetOpt("default_host", hostname->GetText(), 1); kpinterface->prefs->SetOpt("default_port", hostport->GetText(), 1); kpinterface->prefs->SetOpt("autoconnect", autoconcheck->GetChecked() ? "true" : "false", 1); globalreg->panel_interface->KillPanel(this); } else if (in_button == cancelbutton) { // Cancel and close globalreg->panel_interface->KillPanel(this); } return; } Kis_OrderlistPref_Component::Kis_OrderlistPref_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Scrollable_Table(in_globalreg, in_panel) { globalreg = in_globalreg; selected = -1; orderable = 0; enable_fid = -1; field_yes = field_no = ""; } Kis_OrderlistPref_Component::~Kis_OrderlistPref_Component() { } void Kis_OrderlistPref_Component::SetOrderable(int in_order) { orderable = in_order; } void Kis_OrderlistPref_Component::SetEnableField(int in_field, string in_yes, string in_no) { enable_fid = in_field; field_yes = in_yes; field_no = in_no; } void Kis_OrderlistPref_Component::SetColumnField(int in_field) { column_fid = in_field; } int Kis_OrderlistPref_Component::KeyPress(int in_key) { if (visible == 0) return 0; if (orderable) { // Just swap fields around and then treat it like a user-keyed move if (in_key == '-' && selected > 0) { row_data *bak = data_vec[selected - 1]; data_vec[selected - 1] = data_vec[selected]; data_vec[selected] = bak; Kis_Scrollable_Table::KeyPress(KEY_UP); } if (in_key == '+' && selected < (int) data_vec.size() - 1) { row_data *bak = data_vec[selected + 1]; data_vec[selected + 1] = data_vec[selected]; data_vec[selected] = bak; Kis_Scrollable_Table::KeyPress(KEY_DOWN); } } if (enable_fid >= 0) { if ((in_key == ' ' || in_key == '\n') && (int) data_vec[selected]->data.size() > enable_fid) { // Toggle the enable field of the current row if (data_vec[selected]->data[enable_fid] == field_no) data_vec[selected]->data[enable_fid] = field_yes; else data_vec[selected]->data[enable_fid] = field_no; } } return Kis_Scrollable_Table::KeyPress(in_key); } string Kis_OrderlistPref_Component::GetStringOrderList() { string ret; if (column_fid < 0) return ""; for (unsigned int x = 0; x < data_vec.size(); x++) { if (enable_fid >= 0 && (int) data_vec[x]->data.size() > enable_fid && (int) data_vec[x]->data.size() > column_fid) { if (data_vec[x]->data[enable_fid] == field_yes) { ret += ((x > 0) ? string(",") : string("")) + data_vec[x]->data[column_fid]; } } } return ret; } int ColumnPrefButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ColumnPref_Panel *) aux)->ButtonAction(component); return 1; } Kis_ColumnPref_Panel::Kis_ColumnPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { orderlist = new Kis_OrderlistPref_Component(globalreg, this); helptext = new Kis_Free_Text(globalreg, this); cancelbutton = new Kis_Button(globalreg, this); okbutton = new Kis_Button(globalreg, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColumnPrefButtonCB, this); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ColumnPrefButtonCB, this); AddComponentVec(orderlist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); tab_pos = 0; active_component = orderlist; orderlist->Activate(1); SetTitle("Column Preferences"); // Set the titles, pref and enable columns, and re-ordering vector titles; Kis_Scrollable_Table::title_data t; t.width = 16; t.title = "Column"; t.alignment = 0; titles.push_back(t); t.width = 4; t.title = "Show"; t.alignment = 0; titles.push_back(t); t.width = 30; t.title = "Description"; t.alignment = 0; titles.push_back(t); orderlist->AddTitles(titles); orderlist->SetColumnField(0); orderlist->SetEnableField(1, "Yes", "No"); orderlist->SetOrderable(1); helptext->SetText("Select with space, change order with +/-"); okbutton->SetText("Save"); cancelbutton->SetText("Cancel"); orderlist->Show(); helptext->Show(); okbutton->Show(); cancelbutton->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); vbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); bbox->SetPreferredSize(0, 1); bbox->SetMinSize(0, 1); bbox->Show(); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); vbox->Pack_End(orderlist, 1, 0); vbox->Pack_End(helptext, 0, 0); vbox->Pack_End(bbox, 0, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); pref = ""; Position(WIN_CENTER(20, 60)); } Kis_ColumnPref_Panel::~Kis_ColumnPref_Panel() { } void Kis_ColumnPref_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); vbox->SetPosition(1, 2, in_x - 1, in_y - 3); } void Kis_ColumnPref_Panel::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); wattrset(win, text_color); for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_DRAW) == 0) continue; pan_comp_vec[x].comp->DrawComponent(); } wmove(win, 0, 0); } void Kis_ColumnPref_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { if (pref != "") { kpinterface->prefs->SetOpt(pref, orderlist->GetStringOrderList(), time(0)); } globalreg->panel_interface->KillPanel(this); } else if (in_button == cancelbutton) { // Cancel and close globalreg->panel_interface->KillPanel(this); } return; } void Kis_ColumnPref_Panel::AddColumn(string colname, string description) { pref_cols p; p.colname = colname; p.description = description; p.queued = 0; pref_vec.push_back(p); } void Kis_ColumnPref_Panel::ColumnPref(string in_pref, string name) { vector curprefs = StrTokenize(kpinterface->prefs->FetchOpt(in_pref), ","); vector fdata; int k = 0; pref = in_pref; fdata.push_back("col"); fdata.push_back("enb"); fdata.push_back("dsc"); // Enable the fields for (unsigned int cp = 0; cp < curprefs.size(); cp++) { for (unsigned int sp = 0; sp < pref_vec.size(); sp++) { if (StrLower(pref_vec[sp].colname) == StrLower(curprefs[cp])) { fdata[0] = pref_vec[sp].colname; fdata[1] = "Yes"; fdata[2] = pref_vec[sp].description; orderlist->ReplaceRow(k++, fdata); pref_vec[sp].queued = 1; } } } // Add the other fields we know about which weren't in the preferences for (unsigned int sp = 0; sp < pref_vec.size(); sp++) { if (pref_vec[sp].queued) continue; fdata[0] = pref_vec[sp].colname; fdata[1] = "No"; fdata[2] = pref_vec[sp].description; orderlist->ReplaceRow(k++, fdata); pref_vec[sp].queued = 1; } SetTitle(name + " Column Preferences"); } int GpsconfButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_GpsPref_Panel *) aux)->ButtonAction(component); return 1; } Kis_GpsPref_Panel::Kis_GpsPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { metrad = new Kis_Radiobutton(globalreg, this); metrad->SetText("Metric"); metrad->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); metrad->Show(); metrad->SetChecked(1); AddComponentVec(metrad, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); engrad = new Kis_Radiobutton(globalreg, this); engrad->SetText("English"); engrad->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); engrad->Show(); engrad->SetChecked(1); AddComponentVec(engrad, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); engrad->LinkRadiobutton(metrad); metrad->LinkRadiobutton(engrad); okbutton = new Kis_Button(globalreg, this); okbutton->SetText("OK"); okbutton->Show(); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetText("Cancel"); cancelbutton->Show(); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); SetTitle("Configure GPS"); cbox = new Kis_Panel_Packbox(globalreg, this); cbox->SetPackH(); cbox->SetHomogenous(1); cbox->SetSpacing(1); cbox->SetCenter(1); AddComponentVec(cbox, KIS_PANEL_COMP_DRAW); cbox->Pack_End(metrad, 0, 0); cbox->Pack_End(engrad, 0, 0); cbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(0); bbox->SetCenter(1); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); bbox->Show(); helptext = new Kis_Free_Text(globalreg, this); helptext->SetText("Display GPS in Metric (km) or English (miles)"); helptext->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(helptext, 0, 0); vbox->Pack_End(cbox, 1, 0); vbox->Pack_End(bbox, 0, 0); vbox->Show(); tab_pos = 0; metrad->Activate(1); active_component = metrad; if (StrLower(kpinterface->prefs->FetchOpt("GPSUNIT")) != "metric") { engrad->SetChecked(1); } else { metrad->SetChecked(1); } main_component = vbox; Position(WIN_CENTER(10, 70)); } Kis_GpsPref_Panel::~Kis_GpsPref_Panel() { } void Kis_GpsPref_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { Kis_Panel::Position(in_sy, in_sx, in_y, in_x); vbox->SetPosition(1, 1, in_x - 1, in_y - 2); } void Kis_GpsPref_Panel::DrawPanel() { Kis_Panel::DrawPanel(); } void Kis_GpsPref_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { if (engrad->GetChecked()) { kpinterface->prefs->SetOpt("GPSUNIT", "english", 1); } else { kpinterface->prefs->SetOpt("GPSUNIT", "metric", 1); } kpinterface->KillPanel(this); } else if (in_button == cancelbutton) { kpinterface->KillPanel(this); } } int StartupButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_StartupPref_Panel *) aux)->ButtonAction(component); return 1; } Kis_StartupPref_Panel::Kis_StartupPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { startkis_check = new Kis_Checkbox(globalreg, this); startkis_check->SetText("Open Kismet server launch window automatically"); startkis_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, StartupButtonCB, this); startkis_check->Show(); AddComponentVec(startkis_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); startkisprompt_check = new Kis_Checkbox(globalreg, this); startkisprompt_check->SetText("Ask about launching server on startup"); startkisprompt_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, StartupButtonCB, this); startkisprompt_check->Show(); AddComponentVec(startkisprompt_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); startcons_check = new Kis_Checkbox(globalreg, this); startcons_check->SetText("Show Kismet server console by default"); startcons_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, StartupButtonCB, this); startcons_check->Show(); AddComponentVec(startcons_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); stopkis_check = new Kis_Checkbox(globalreg, this); stopkis_check->SetText("Shut down Kismet server on exit automatically"); stopkis_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, StartupButtonCB, this); stopkis_check->Show(); AddComponentVec(stopkis_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); stopkisprompt_check = new Kis_Checkbox(globalreg, this); stopkisprompt_check->SetText("Prompt before shutting down Kismet server"); stopkisprompt_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, StartupButtonCB, this); stopkisprompt_check->Show(); AddComponentVec(stopkisprompt_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton = new Kis_Button(globalreg, this); okbutton->SetText("OK"); okbutton->Show(); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetText("Cancel"); cancelbutton->Show(); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, GpsconfButtonCB, this); SetTitle("Startup Options"); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(0); bbox->SetCenter(1); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); bbox->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(startkis_check, 0, 0); vbox->Pack_End(startkisprompt_check, 0, 0); vbox->Pack_End(startcons_check, 0, 0); vbox->Pack_End(stopkis_check, 0, 0); vbox->Pack_End(stopkisprompt_check, 0, 0); vbox->Pack_End(bbox, 0, 0); vbox->Show(); main_component = vbox; tab_pos = 0; startkis_check->Activate(1); active_component = startkis_check; // if (StrLower(kpinterface->prefs->FetchOpt("STARTUP_SERVER")) == "true" || // kpinterface->prefs->FetchOpt("STARTUP_SERVER") == "") { if (kpinterface->prefs->FetchOptBoolean("STARTUP_SERVER", 1)) { startkis_check->SetChecked(1); } else { startkis_check->SetChecked(0); } // if (StrLower(kpinterface->prefs->FetchOpt("STARTUP_PROMPTSERVER")) == "true" || // kpinterface->prefs->FetchOpt("STARTUP_PROMPTSERVER") == "") { if (kpinterface->prefs->FetchOptBoolean("STARTUP_PROMPTSERVER", 1)) { startkisprompt_check->SetChecked(1); } else { startkisprompt_check->SetChecked(0); } // if (StrLower(kpinterface->prefs->FetchOpt("STARTUP_CONSOLE")) == "true" || // kpinterface->prefs->FetchOpt("STARTUP_CONSOLE") == "") { if (kpinterface->prefs->FetchOptBoolean("STARTUP_CONSOLE", 1)) { startcons_check->SetChecked(1); } else { startcons_check->SetChecked(0); } // if (StrLower(kpinterface->prefs->FetchOpt("STOP_SERVER")) == "true" || // kpinterface->prefs->FetchOpt("STOP_SERVER") == "") { if (kpinterface->prefs->FetchOptBoolean("STOP_SERVER", 1)) { stopkis_check->SetChecked(1); } else { stopkis_check->SetChecked(0); } // if (StrLower(kpinterface->prefs->FetchOpt("STOP_PROMPTSERVER")) == "true" || // kpinterface->prefs->FetchOpt("STOP_PROMPTSERVER") == "") { if (kpinterface->prefs->FetchOptBoolean("STOP_PROMPTSERVER", 1)) { stopkisprompt_check->SetChecked(1); } else { stopkisprompt_check->SetChecked(0); } Position(WIN_CENTER(14, 70)); } Kis_StartupPref_Panel::~Kis_StartupPref_Panel() { } void Kis_StartupPref_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == okbutton) { if (startkis_check->GetChecked()) { kpinterface->prefs->SetOpt("STARTUP_SERVER", "true", 1); } else { kpinterface->prefs->SetOpt("STARTUP_SERVER", "false", 1); } if (startkisprompt_check->GetChecked()) { kpinterface->prefs->SetOpt("STARTUP_PROMPTSERVER", "true", 1); } else { kpinterface->prefs->SetOpt("STARTUP_PROMPTSERVER", "false", 1); } if (startcons_check->GetChecked()) { kpinterface->prefs->SetOpt("STARTUP_CONSOLE", "true", 1); } else { kpinterface->prefs->SetOpt("STARTUP_CONSOLE", "false", 1); } if (stopkis_check->GetChecked()) { kpinterface->prefs->SetOpt("STOP_SERVER", "true", 1); } else { kpinterface->prefs->SetOpt("STOP_SERVER", "false", 1); } if (stopkisprompt_check->GetChecked()) { kpinterface->prefs->SetOpt("STOP_PROMPTSERVER", "true", 1); } else { kpinterface->prefs->SetOpt("STOP_PROMPTSERVER", "false", 1); } kpinterface->KillPanel(this); } else if (in_button == cancelbutton) { kpinterface->KillPanel(this); } } #if 0 int AudioPickerCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AudioPicker_Panel *) aux)->Action(component, status); return 1; } Kis_AudioPicker_Panel::Kis_AudioPicker_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { filelist = new Kis_Filepicker(globalreg, this); filelist->Show(); AddComponentVec(filelist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); directory = new Kis_Single_Input(globalreg, this); directory->SetLabel("Dir:", LABEL_POS_LEFT); directory->SetCharFilter(FILTER_ALPHANUMSYM); directory->Show(); AddComponentVec(directory, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); dirbutton = new Kis_Button(globalreg, this); dirbutton->SetLabel("Change Dir"); dirbutton->Show(); dirbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPickerCB, this); enablecheck = new Kis_Checkbox(globalreg, this); enablecheck->SetLabel("Play Sound"); enablecheck->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPickerCB, this); AddComponentVec(enablecheck, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); okbutton = new Kis_Button(globalreg, this); okbutton->SetLabel("Save"); okbutton->Show(); okbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPickerCB, this); AddComponentVec(okbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); cancelbutton = new Kis_Button(globalreg, this); cancelbutton->SetLabel("Cancel"); cancelbutton->Show(); cancelbutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPickerCB, this); AddComponentVec(cancelbutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("Pick Sound"); dbox = new Kis_Panel_Packbox(globalreg, this); dbox->SetPackH(); dbox->SetHomogenous(0); dbox->SetSpacing(0); dbox->SetCenter(1); AddComponentVec(dbox, KIS_PANEL_COMP_DRAW); dbox->Pack_End(directory, 1, 0); dbox->Pack_End(dirbutton, 0, 0); dbox->Show(); bbox = new Kis_Panel_Packbox(globalreg, this); bbox->SetPackH(); bbox->SetHomogenous(1); bbox->SetSpacing(1); bbox->SetCenter(1); AddComponentVec(bbox, KIS_PANEL_COMP_DRAW); bbox->Pack_End(cancelbutton, 0, 0); bbox->Pack_End(okbutton, 0, 0); bbox->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(filelist, 1, 0); vbox->Pack_End(dbox, 0, 0); vbox->Pack_End(enablecheck, 0, 0); vbox->Pack_End(bbox, 0, 0); vbox->Show(); main_component = vbox; SetActiveComponent(filelist); Position(WIN_CENTER(15, 70)); } Kis_AudioPicker_Panel::~Kis_AudioPicker_Panel() { } void Kis_AudioPicker_Panel::SetPref(string in_trigger, string in_enable, string in_file) { trigger = in_trigger; size_t dpos; enablecheck->SetChecked(in_enable == "true"); if ((dpos = in_file.rfind("/")) == string::npos) { filelist->SetDirectory(kpinterface->prefs->FetchOpt("SOUND_PREFIX")); filelist->SetFile(in_file); directory->SetText(kpinterface->prefs->FetchOpt("SOUND_PREFIX"), -1, -1); } else { filelist->SetDirectory(in_file.substr(0, dpos)); filelist->SetFile(in_file.substr(dpos + 1, in_file.length())); directory->SetText(in_file.substr(0, dpos), -1, -1); } } void Kis_AudioPicker_Panel::Action(Kis_Panel_Component *in_component, int in_status) { if (in_component == cancelbutton) { kpinterface->KillPanel(this); return; } if (in_component == dirbutton) { filelist->SetDirectory(directory->GetText()); return; } if (in_component == okbutton) { string d = filelist->GetDirectory(); vector sd = filelist->GetSelectedData(); struct stat sbuf; if (sd.size() == 0) { kpinterface->RaiseAlert("No selected file", InLineWrap("No file to play was selected, pick one or cancel", 0, 50)); return; } if (d == kpinterface->prefs->FetchOpt("SOUND_PREFIX") || (d + "/") == kpinterface->prefs->FetchOpt("SOUND_PREFIX")) d = sd[0]; else d += sd[0]; if (stat(d.c_str(), &sbuf) != 0) { kpinterface->RaiseAlert("Selected file missing", InLineWrap(string("Selected file is missing (") + string(strerror(errno)) + string("), pick another or cancel"), 0, 50)); return; } if (S_ISDIR(sbuf.st_mode)) { kpinterface->RaiseAlert("Selected directory", InLineWrap("Selected is a directory, pick a file or cancel", 0, 50)); return; } kpinterface->prefs->SetOpt("SOUND", trigger + string(",") + (enablecheck->GetChecked() ? "true" : "false") + string(",") + d, 1); } } #endif int AudioPrefCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AudioPref_Panel *) aux)->Action(component, status); return 1; } Kis_AudioPref_Panel::Kis_AudioPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { audiolist = new Kis_Scrollable_Table(globalreg, this); audiolist->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPrefCB, this); AddComponentVec(audiolist, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); vector titles; Kis_Scrollable_Table::title_data t; t.width = 0; t.title = "Sound"; t.alignment = 0; titles.push_back(t); t.width = 4; t.title = "Play"; t.alignment = 0; titles.push_back(t); audiolist->SetPreferredSize(0, 6); audiolist->AddTitles(titles); audiolist->Show(); vector aprefs = kpinterface->prefs->FetchOptVec("SOUND"); vector tdata; tdata.push_back(""); tdata.push_back(""); keys.clear(); for (unsigned int a = 0; a < aprefs.size(); a++) { vector pvec = StrTokenize(aprefs[a], ","); int valid = 0; if (pvec.size() != 2) continue; pvec[0] = StrLower(pvec[0]); // Only process the sounds we know about if (pvec[0] == "alert") { valid = 1; tdata[0] = "Alert"; } else if (pvec[0] == "packet") { valid = 1; tdata[0] = "Packet"; } else if (pvec[0] == "newnet") { valid = 1; tdata[0] = "New Network"; } else if (pvec[0] == "gpslock") { valid = 1; tdata[0] = "GPS Lock"; } else if (pvec[0] == "gpslost") { valid = 1; tdata[0] = "GPS Lost"; } if (valid) { string enable = (StrLower(pvec[1]) == "true") ? "Yes" : "No"; tdata[1] = enable; audiolist->ReplaceRow(a, tdata); keys.push_back(a); } } sound_check = new Kis_Checkbox(globalreg, this); sound_check->SetText("Enable Sound"); // sound_check->SetChecked(StrLower(kpinterface->prefs->FetchOpt("SOUNDENABLE")) == // "true"); sound_check->SetChecked(kpinterface->prefs->FetchOptBoolean("SOUNDENABLE", 0)); sound_check->Show(); sound_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPrefCB, this); AddComponentVec(sound_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speech_check = new Kis_Checkbox(globalreg, this); speech_check->SetText("Enable Speech"); // speech_check->SetChecked(StrLower(kpinterface->prefs->FetchOpt("SPEECHENABLE")) == // "true"); speech_check->SetChecked(kpinterface->prefs->FetchOptBoolean("SPEECHENABLE", 0)); speech_check->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPrefCB, this); speech_check->Show(); AddComponentVec(speech_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); sound_player = new Kis_Single_Input(globalreg, this); sound_player->SetLabel("Player", LABEL_POS_LEFT); sound_player->SetText(kpinterface->prefs->FetchOpt("SOUNDBIN"), -1, -1); sound_player->SetCharFilter(FILTER_ALPHANUMSYM); sound_player->SetTextLen(64); sound_player->Show(); AddComponentVec(sound_player, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); config_speech_button = new Kis_Button(globalreg, this); config_speech_button->SetText("Configure Speech"); config_speech_button->Show(); config_speech_button->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPrefCB, this); AddComponentVec(config_speech_button, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); close_button = new Kis_Button(globalreg, this); close_button->SetText("Close"); close_button->Show(); close_button->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AudioPrefCB, this); AddComponentVec(close_button, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("Sound Options"); cbox = new Kis_Panel_Packbox(globalreg, this); cbox->SetPackH(); cbox->SetHomogenous(1); cbox->SetSpacing(0); cbox->SetCenter(1); AddComponentVec(cbox, KIS_PANEL_COMP_DRAW); cbox->Pack_End(sound_check, 0, 0); cbox->Pack_End(speech_check, 0, 0); cbox->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(audiolist, 1, 0); vbox->Pack_End(cbox, 0, 0); vbox->Pack_End(sound_player, 0, 0); vbox->Pack_End(config_speech_button, 0, 0); vbox->Pack_End(close_button, 0, 0); vbox->Show(); main_component = vbox; SetActiveComponent(audiolist); Position(WIN_CENTER(15, 50)); } Kis_AudioPref_Panel::~Kis_AudioPref_Panel() { } void Kis_AudioPref_Panel::Action(Kis_Panel_Component *in_component, int in_status) { if (in_component == close_button) { vector prefs; for (unsigned int x = 0; x < keys.size(); x++) { string h; vector td = audiolist->GetRow(keys[x]); if (td.size() != 2) continue; if (td[0] == "Alert") h = "alert"; else if (td[0] == "Packet") h = "packet"; else if (td[0] == "New Network") h = "newnet"; else if (td[0] == "GPS Lost") h = "gpslost"; else if (td[0] == "GPS Lock") h = "gpslock"; else { _MSG("INTERNAL ERROR: SNDPREF saw '" + td[0] + "' and didn't know what " "it was", MSGFLAG_ERROR); continue; } prefs.push_back(h + string(",") + (td[1] == "Yes" ? "true" : "false")); } kpinterface->prefs->SetOptVec("sound", prefs, 1); kpinterface->prefs->SetOpt("SOUNDENABLE", sound_check->GetChecked() ? "true" : "false", 1); globalreg->soundctl->SetSoundEnable(sound_check->GetChecked()); kpinterface->prefs->SetOpt("SPEECHENABLE", speech_check->GetChecked() ? "true" : "false", 1); globalreg->soundctl->SetSpeechEnable(sound_check->GetChecked()); if (sound_player->GetText() != kpinterface->prefs->FetchOpt("SOUNDBIN")) { kpinterface->prefs->SetOpt("SOUNDBIN", sound_player->GetText(), 0); globalreg->soundctl->SetPlayer(sound_player->GetText()); } // Reload the prefs kpinterface->FetchMainPanel()->LoadAudioPrefs(); kpinterface->KillPanel(this); return; } if (in_component == audiolist) { vector selrow = audiolist->GetSelectedData(); if (selrow.size() == 0) return; if (selrow[1] == "Yes") selrow[1] = "No"; else selrow[1] = "Yes"; audiolist->ReplaceRow(audiolist->GetSelected(), selrow); } if (in_component == config_speech_button) { Kis_SpeechPref_Panel *sp = new Kis_SpeechPref_Panel(globalreg, kpinterface); kpinterface->AddPanel(sp); } } void Kis_AudioPref_Panel::DrawPanel() { Kis_Panel::DrawPanel(); } int SpeechPrefCB(COMPONENT_CALLBACK_PARMS) { ((Kis_SpeechPref_Panel *) aux)->Action(component, status); return 1; } Kis_SpeechPref_Panel::Kis_SpeechPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { vector ft; speechtype_text = new Kis_Free_Text(globalreg, this); ft.clear(); ft.push_back("See the Kismet README for how speech strings are expanded"); speechtype_text->SetText(ft); speechtype_text->Show(); speech_new = new Kis_Single_Input(globalreg, this); speech_new->SetLabel("New", LABEL_POS_LEFT); speech_new->SetCharFilter(FILTER_ALPHANUMSYM); speech_new->SetTextLen(64); AddComponentVec(speech_new, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speech_new->Show(); speech_alert = new Kis_Single_Input(globalreg, this); speech_alert->SetLabel("Alert", LABEL_POS_LEFT); speech_alert->SetCharFilter(FILTER_ALPHANUMSYM); speech_alert->SetTextLen(64); AddComponentVec(speech_alert, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speech_alert->Show(); speech_gpslost = new Kis_Single_Input(globalreg, this); speech_gpslost->SetLabel("GPS Lost", LABEL_POS_LEFT); speech_gpslost->SetCharFilter(FILTER_ALPHANUMSYM); speech_gpslost->SetTextLen(64); AddComponentVec(speech_gpslost, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speech_gpslost->Show(); speech_gpslock = new Kis_Single_Input(globalreg, this); speech_gpslock->SetLabel("GPS OK", LABEL_POS_LEFT); speech_gpslock->SetCharFilter(FILTER_ALPHANUMSYM); speech_gpslock->SetTextLen(64); AddComponentVec(speech_gpslock, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speech_gpslock->Show(); speechplayer_text = new Kis_Free_Text(globalreg, this); ft.clear(); ft.push_back("If using Festival, be sure to enable the Festival mode checkbox"); speechplayer_text->SetText(ft); speechplayer_text->Show(); speaker = new Kis_Single_Input(globalreg, this); speaker->SetLabel("Speech Player", LABEL_POS_LEFT); speaker->SetCharFilter(FILTER_ALPHANUMSYM); speaker->SetTextLen(64); AddComponentVec(speaker, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); speaker->Show(); speaker->SetText(kpinterface->prefs->FetchOpt("SPEECHBIN"), -1, -1); fest_check = new Kis_Checkbox(globalreg, this); fest_check->SetLabel("Festival Mode"); AddComponentVec(fest_check, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); fest_check->Show(); fest_check->SetChecked( StrLower(kpinterface->prefs->FetchOpt("SPEECHTYPE")) == "festival"); encode_text = new Kis_Free_Text(globalreg, this); ft.clear(); ft.push_back("SSID encoding:"); encode_text->SetText(ft); encode_text->Show(); encode_none_radio = new Kis_Radiobutton(globalreg, this); encode_none_radio->SetText("Normal"); encode_none_radio->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpeechPrefCB, this); encode_none_radio->Show(); encode_none_radio->SetChecked(1); AddComponentVec(encode_none_radio, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); encode_nato_radio = new Kis_Radiobutton(globalreg, this); encode_nato_radio->SetText("Nato"); encode_nato_radio->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpeechPrefCB, this); encode_nato_radio->Show(); encode_nato_radio->SetChecked(1); AddComponentVec(encode_nato_radio, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); encode_spell_radio = new Kis_Radiobutton(globalreg, this); encode_spell_radio->SetText("Spell"); encode_spell_radio->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpeechPrefCB, this); encode_spell_radio->Show(); encode_spell_radio->SetChecked(1); AddComponentVec(encode_spell_radio, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); encode_none_radio->LinkRadiobutton(encode_nato_radio); encode_none_radio->LinkRadiobutton(encode_spell_radio); encode_nato_radio->LinkRadiobutton(encode_none_radio); encode_nato_radio->LinkRadiobutton(encode_spell_radio); encode_spell_radio->LinkRadiobutton(encode_nato_radio); encode_spell_radio->LinkRadiobutton(encode_none_radio); if (StrLower(kpinterface->prefs->FetchOpt("SPEECHENCODING")) == "nato") { encode_nato_radio->SetChecked(1); } else if (StrLower(kpinterface->prefs->FetchOpt("SPEECHENCODING")) == "spell") { encode_spell_radio->SetChecked(1); } else { encode_none_radio->SetChecked(1); } close_button = new Kis_Button(globalreg, this); close_button->SetText("Close"); close_button->Show(); close_button->SetCallback(COMPONENT_CBTYPE_ACTIVATED, SpeechPrefCB, this); AddComponentVec(close_button, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("Sound Options"); rbox = new Kis_Panel_Packbox(globalreg, this); rbox->SetPackH(); rbox->SetHomogenous(1); rbox->SetSpacing(0); rbox->SetCenter(1); AddComponentVec(rbox, KIS_PANEL_COMP_DRAW); rbox->Pack_End(encode_none_radio, 0, 0); rbox->Pack_End(encode_nato_radio, 0, 0); rbox->Pack_End(encode_spell_radio, 0, 0); rbox->Show(); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox2 = new Kis_Panel_Packbox(globalreg, this); vbox2->SetPackV(); vbox2->SetHomogenous(0); vbox2->SetSpacing(0); AddComponentVec(vbox2, KIS_PANEL_COMP_DRAW); vbox2->Pack_End(speechtype_text, 0, 0); vbox2->Pack_End(speech_new, 0, 0); vbox2->Pack_End(speech_alert, 0, 0); vbox2->Pack_End(speech_gpslost, 0, 0); vbox2->Pack_End(speech_gpslock, 0, 0); vbox2->SetPreferredSize(0, 5); vbox2->Show(); vbox->Pack_End(vbox2, 0, 0); vbox->Pack_End(speechplayer_text, 0, 0); vbox->Pack_End(speaker, 0, 0); vbox->Pack_End(fest_check, 0, 0); vbox->Pack_End(encode_text, 0, 0); vbox->Pack_End(rbox, 0, 0); vbox->Pack_End(close_button, 0, 0); vbox->Show(); main_component = vbox; SetActiveComponent(speech_new); Position(WIN_CENTER(18, 50)); vector spref = kpinterface->prefs->FetchOptVec("speech"); vector sf; string st; for (unsigned int x = 0; x < spref.size(); x++) { sf = QuoteStrTokenize(spref[x], ","); if (sf.size() != 2) continue; st = StrLower(sf[0]); if (st == "new") speech_new->SetText(sf[1], -1, -1); else if (st == "alert") speech_alert->SetText(sf[1], -1, -1); else if (st == "gpslost") speech_gpslost->SetText(sf[1], -1, -1); else if (st == "gpslock") speech_gpslock->SetText(sf[1], -1, -1); } } Kis_SpeechPref_Panel::~Kis_SpeechPref_Panel() { } void Kis_SpeechPref_Panel::Action(Kis_Panel_Component *in_component, int in_status) { if (in_component == close_button) { vector prefs; prefs.push_back("new,\"" + speech_new->GetText() + "\""); prefs.push_back("alert,\"" + speech_alert->GetText() + "\""); prefs.push_back("gpslost,\"" + speech_gpslost->GetText() + "\""); prefs.push_back("gpslock,\"" + speech_gpslock->GetText() + "\""); kpinterface->prefs->SetOptVec("SPEECH", prefs, 1); kpinterface->prefs->SetOpt("SPEECHBIN", speaker->GetText(), 1); kpinterface->prefs->SetOpt("SPEECHTYPE", fest_check->GetChecked() ? "festival" : "raw", 1); globalreg->soundctl->SetSpeaker(speaker->GetText(), fest_check->GetChecked() ? "festival" : "raw"); if (encode_none_radio->GetChecked()) { kpinterface->prefs->SetOpt("SPEECHENCODING", "speech", 1); globalreg->soundctl->SetSpeechEncode("speech"); } else if (encode_nato_radio->GetChecked()) { kpinterface->prefs->SetOpt("SPEECHENCODING", "nato", 1); globalreg->soundctl->SetSpeechEncode("nato"); } else if (encode_spell_radio->GetChecked()) { kpinterface->prefs->SetOpt("SPEECHENCODING", "spell", 1); globalreg->soundctl->SetSpeechEncode("spell"); } kpinterface->KillPanel(this); return; } } int WarnPrefCB(COMPONENT_CALLBACK_PARMS) { ((Kis_WarnPref_Panel *) aux)->Action(component, status); return 1; } Kis_WarnPref_Panel::Kis_WarnPref_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf): Kis_Panel(in_globalreg, in_intf) { warntable = new Kis_Scrollable_Table(globalreg, this); warntable->SetCallback(COMPONENT_CBTYPE_ACTIVATED, WarnPrefCB, this); AddComponentVec(warntable, (KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT)); vector titles; Kis_Scrollable_Table::title_data t; t.width = 0; t.title = "Warning"; t.alignment = 0; titles.push_back(t); t.width = 7; t.title = "Display"; t.alignment = 0; titles.push_back(t); t.width = -1; t.title = "[pref]"; t.alignment = 0; titles.push_back(t); warntable->SetPreferredSize(0, 6); warntable->AddTitles(titles); warntable->Show(); vector ft; closebutton = new Kis_Button(globalreg, this); closebutton->SetText("Close"); closebutton->Show(); closebutton->SetCallback(COMPONENT_CBTYPE_ACTIVATED, WarnPrefCB, this); AddComponentVec(closebutton, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); SetTitle("Warning Options"); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(1); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); vbox->Pack_End(warntable, 1, 0); vbox->Pack_End(closebutton, 0, 0); vbox->Show(); main_component = vbox; SetActiveComponent(warntable); Position(WIN_CENTER(10, 45)); vector td; k = 0; td.push_back(""); td.push_back(""); td.push_back(""); td[0] = "Source Warnings"; td[2] = "WARN_SOURCEWARN"; // if (kpinterface->prefs->FetchOpt(td[2]) != "false") { if (kpinterface->prefs->FetchOptBoolean(td[2], 1)) { td[1] = "Yes"; } else { td[1] = "No"; } warntable->ReplaceRow(k++, td); td[0] = "All Sources Errored"; td[2] = "WARN_ALLERRSOURCE"; // if (kpinterface->prefs->FetchOpt(td[2]) != "false") { if (kpinterface->prefs->FetchOptBoolean(td[2], 1)) { td[1] = "Yes"; } else { td[1] = "No"; } warntable->ReplaceRow(k++, td); td[0] = "Running As Root"; td[2] = "STARTUP_WARNROOT"; // if (kpinterface->prefs->FetchOpt(td[2]) != "false") { if (kpinterface->prefs->FetchOptBoolean(td[2], 1)) { td[1] = "Yes"; } else { td[1] = "No"; } warntable->ReplaceRow(k++, td); } Kis_WarnPref_Panel::~Kis_WarnPref_Panel() { } void Kis_WarnPref_Panel::Action(Kis_Panel_Component *in_component, int in_status) { if (in_component == closebutton) { for (int x = 0; x < k; x++) { vector td = warntable->GetRow(x); if (td.size() != 3) continue; kpinterface->prefs->SetOpt(td[2], td[1] == "Yes" ? "true" : "false", 1); } kpinterface->KillPanel(this); return; } if (in_component == warntable) { vector selrow = warntable->GetSelectedData(); if (selrow.size() != 3) return; if (selrow[1] == "Yes") selrow[1] = "No"; else selrow[1] = "Yes"; warntable->ReplaceRow(warntable->GetSelected(), selrow); } } #endif kismet-2013-03-R1b/dumpfile_tuntap.cc0000664000175000017500000002276212124602454017173 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "dumpfile_tuntap.h" #include "ifcontrol.h" #include "ipc_remote.h" #ifndef SYS_CYGWIN int dft_ipc_open(IPC_CMD_PARMS) { if (parent) { // If we're the parent, we use this as a signal that we've opened it // and we need to pull the file descriptor if (len < (int) sizeof(ipc_dft_open)) return 0; globalreg->packetchain->RegisterHandler(&dumpfiletuntap_chain_hook, (void *) auxptr, CHAINPOS_LOGGING, -100); globalreg->RegisterDumpFile((Dumpfile_Tuntap *) auxptr); return ((Dumpfile_Tuntap *) auxptr)->GetTapFd(); } else { // If we're the child, we now know our tap device name from the // config parser in the parent, record it and open // fname = string(((ipc_dft_open *) data)->tapdevice); ipc_dft_open *dfo = (ipc_dft_open *) data; ((Dumpfile_Tuntap *) auxptr)->SetTapDevice(string((char *) dfo->tapdevice)); ((Dumpfile_Tuntap *) auxptr)->OpenTuntap(); return 1; } } int dft_ipc_sync_complete(IPC_CMD_PARMS) { if (parent) return 0; ((Dumpfile_Tuntap *) auxptr)->RegisterIPC(); return 1; } int dumpfiletuntap_chain_hook(CHAINCALL_PARMS) { Dumpfile_Tuntap *auxptr = (Dumpfile_Tuntap *) auxdata; return auxptr->chain_handler(in_pack); } Dumpfile_Tuntap::Dumpfile_Tuntap() { fprintf(stderr, "FATAL OOPS: Dumpfile_Tuntap called with no globalreg\n"); exit(1); } Dumpfile_Tuntap::Dumpfile_Tuntap(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; tuntap_fd = -1; type = "tuntap"; // If we have a config, push it to the other side if (globalreg->kismet_config != NULL) { //if (globalreg->kismet_config->FetchOpt("tuntap_export") != "true") { if (globalreg->kismet_config->FetchOptBoolean("tuntap_export", 0) != 1) { return; } if ((fname = globalreg->kismet_config->FetchOpt("tuntap_device")) == "") { _MSG("No 'tuntap_device' specified in Kismet config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } } // Register the IPC channel if (globalreg->rootipc != NULL) { ipc_sync_id = globalreg->rootipc->RegisterIPCCmd(&dft_ipc_sync_complete, NULL, this, "SYNCCOMPLETE"); ipc_trigger_id = globalreg->rootipc->RegisterIPCCmd(&dft_ipc_open, NULL, this, "TUNTAP_TRIGGER"); } } void Dumpfile_Tuntap::RegisterIPC() { if (globalreg->rootipc != NULL) { ipc_trigger_id = globalreg->rootipc->RegisterIPCCmd(&dft_ipc_open, NULL, this, "TUNTAP_TRIGGER"); } } Dumpfile_Tuntap::~Dumpfile_Tuntap() { globalreg->packetchain->RemoveHandler(&dumpfiletuntap_chain_hook, CHAINPOS_LOGGING); if (tuntap_fd >= 0) { close(tuntap_fd); tuntap_fd = -1; _MSG("Closed tun/tap virtual interface '" + fname + "'", MSGFLAG_INFO); } } int Dumpfile_Tuntap::OpenTuntap() { // Open the tuntap device and optionally send it over IPC if we're running // split-priv char errstr[STATUS_MAX]; if (fname == "") return -1; // fprintf(stderr, "debug- opentuntap %d\n", getpid()); // If we have a file name, and we have IPC, assume we need to send it // to the other side of the IPC if (globalreg->rootipc != NULL && globalreg->rootipc->FetchSpawnPid() > 0) { // fprintf(stderr, "debug- opentuntap rootipc %d\n", getpid()); if (globalreg->rootipc->FetchRootIPCSynced() <0 ) { _MSG("tun/tap driver needs root privileges to create the virtual " "interface, but the root control process doesn't appear to be " "running, tun/tap will not be configured.", MSGFLAG_ERROR); return -1; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_dft_open)); ipc_dft_open *dfto = (ipc_dft_open *) ipc->data; ipc->data_len = sizeof(ipc_dft_open); ipc->ipc_ack = 0; ipc->ipc_cmdnum = ipc_trigger_id; snprintf((char *) dfto->tapdevice, 32, "%s", fname.c_str()); globalreg->rootipc->SendIPC(ipc); return 1; } // fprintf(stderr, "debug- not opentuntap rootipc\n"); #ifdef SYS_LINUX // Linux has dynamic tun-tap, so we allocate our device that way if ((tuntap_fd = open("/dev/net/tun", O_RDWR)) < 0) { if (errno == EACCES) { snprintf(errstr, STATUS_MAX, "Unable to open the tun/tap control " "file (/dev/net/tun), it could not be found. Make sure that " "you have tun/tap support compiled into your kernel, and if " "it is a module, make sure the tun module is loaded. The " "exact error was: %s", strerror(errno)); } else if (errno == ENOENT) { snprintf(errstr, STATUS_MAX, "Unable to open the tun/tap control " "file (/dev/net/tun), write permission was denied. Make " "sure that you are running as a user which has permission " "(typically only root) or that you modified permissions on " "your /dev filesystem. The exact error was: %s", strerror(errno)); } else { snprintf(errstr, STATUS_MAX, "Unable to open the tun/tap control " "file (/dev/net/tun) for writing. The exact error was: %s", strerror(errno)); } _MSG(errstr, MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Create the tap interface struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = (IFF_TAP | IFF_NO_PI); strncpy(ifr.ifr_name, fname.c_str(), sizeof(ifr.ifr_name) - 1); if (ioctl(tuntap_fd, TUNSETIFF, (void *) &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Unable to create the tun/tap interface: %s", strerror(errno)); _MSG(errstr, MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Try to set the link type if (ioctl(tuntap_fd, TUNSETLINK, LNX_LINKTYPE_80211) < 0) { snprintf(errstr, STATUS_MAX, "Unable to set the tun/tap interface link " "type. While Kismet will be able to continue, unless the " "program capturing packets is able to handle a broken link " "type it will not work properly. Make sure you have applied " "the patches to set tun/tap link type. Exact error was: %s", strerror(errno)); _MSG(errstr, MSGFLAG_ERROR); // globalreg->fatal_condition = 1; sleep(1); return -1; } if (ioctl(tuntap_fd, TUNSETNOCSUM, 1) < 0) { _MSG("Unable to disable checksumming on tun/tap interface " + fname + ": " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } #endif // Bring up the interface if (Ifconfig_Delta_Flags(fname.c_str(), errstr, (IFF_UP | IFF_RUNNING | IFF_PROMISC)) < 0) { _MSG(errstr, MSGFLAG_FATAL); _MSG("Failed bringing virtual interface " + fname + " up", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } #ifndef SYS_LINUX // Non-linux systems have fixed tun devices, so we open that if ((tuntap_fd = open(string("/dev/" + fname).c_str(), O_RDWR)) < 0) { _MSG("Unable to open tun/tap interface " + fname + ": " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } #endif _MSG("Opened tun/tap replicator '" + fname + "'", MSGFLAG_INFO); // printf("debug - %d opened tun/tap replicator\n", getpid()); if (globalreg->rootipc != NULL) { // printf("debug - %d - calling senddescriptor\n", getpid()); if (globalreg->rootipc->SendDescriptor(tuntap_fd) < 0) { _MSG("tuntap failed to send tap descriptor over IPC", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_dft_open)); ipc_dft_open *dfto = (ipc_dft_open *) ipc->data; ipc->data_len = sizeof(ipc_dft_open); ipc->ipc_ack = 0; ipc->ipc_cmdnum = ipc_trigger_id; dfto->tapdevice[0] = 0; // printf("debug - %d queueing senddescriptor trigger command\n", getpid()); globalreg->rootipc->SendIPC(ipc); } else { // Otherwise we're running with no privsep so register ourselves globalreg->packetchain->RegisterHandler(&dumpfiletuntap_chain_hook, this, CHAINPOS_LOGGING, -100); globalreg->RegisterDumpFile(this); } return 0; } int Dumpfile_Tuntap::GetTapFd() { // Get the descriptor form the root IPC if (globalreg->rootipc == NULL) return -1; tuntap_fd = globalreg->rootipc->ReceiveDescriptor(); return tuntap_fd; } int Dumpfile_Tuntap::Flush() { // Nothing to see here return 0; } int Dumpfile_Tuntap::chain_handler(kis_packet *in_pack) { if (tuntap_fd < 0) return 0; // Grab the mangled frame if we have it, then try to grab up the list of // data types and die if we can't get anything kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME))) == NULL) { if ((chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME))) == NULL) { return 0; } } } // May not be safe, do we need a ringbuffer? Keep in mind of we have // hanging problems if (write(tuntap_fd, chunk->data, chunk->length) <= 0) return 0; dumped_frames++; return 1; } #endif kismet-2013-03-R1b/packetsource_macusb.cc0000664000175000017500000000340412124602454020005 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(SYS_DARWIN) #include #include #include #include #include #include #include #include "packetsource_macusb.h" #include "packetsourcetracker.h" /* int PacketSource_MacUSB::OpenSource() { return PacketSource_Pcap::OpenSource(); } */ int PacketSource_MacUSB::AutotypeProbe(string in_device) { if (in_device.substr(0, 3) == "tap") { type = "macusb"; return 1; } return 0; } int PacketSource_MacUSB::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("macusb", this, "IEEE80211b", 0); tracker->RegisterPacketProto("macrtl8187", this, "IEEE80211b", 0); return 1; } PacketSource_MacUSB::PacketSource_MacUSB(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { // We override as DLT_IEEE802_11 by default override_dlt = KDLT_IEEE802_11; fcsbytes = 4; } #endif kismet-2013-03-R1b/packetchain.cc0000664000175000017500000002121612124602454016236 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include "globalregistry.h" #include "messagebus.h" #include "configfile.h" #include "packetchain.h" class SortLinkPriority { public: inline bool operator() (const Packetchain::pc_link *x, const Packetchain::pc_link *y) const { if (x->priority < y->priority) return 1; return 0; } }; Packetchain::Packetchain() { fprintf(stderr, "Packetchain() called with no globalregistry\n"); exit(-1); } Packetchain::Packetchain(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; next_componentid = 1; } int Packetchain::RegisterPacketComponent(string in_component) { if (next_componentid >= MAX_PACKET_COMPONENTS) { _MSG("Attempted to register more than the maximum defined number of " "packet components. Report this to the kismet developers along " "with a list of any plugins you might be using.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if (component_str_map.find(StrLower(in_component)) != component_str_map.end()) { return component_str_map[StrLower(in_component)]; } int num = next_componentid++; component_str_map[StrLower(in_component)] = num; component_id_map[num] = StrLower(in_component); return num; } int Packetchain::RemovePacketComponent(int in_id) { string str; if (component_id_map.find(in_id) != component_id_map.end()) { return -1; } str = component_id_map[in_id]; component_id_map.erase(component_id_map.find(in_id)); component_str_map.erase(component_str_map.find(str)); return 1; } kis_packet *Packetchain::GeneratePacket() { kis_packet *newpack = new kis_packet; pc_link *pcl; // Run the frame through the genesis chain incase anything // needs to add something at the beginning for (unsigned int x = 0; x < genesis_chain.size(); x++) { pcl = genesis_chain[x]; // Push it through the genesis chain and destroy it if we fail for some reason if ((*(pcl->callback))(globalreg, pcl->auxdata, newpack) < 0) { DestroyPacket(newpack); return NULL; } } return newpack; } int Packetchain::ProcessPacket(kis_packet *in_pack) { // Run it through every chain vector, ignoring error codes pc_link *pcl; for (unsigned int x = 0; x < postcap_chain.size() && (pcl = postcap_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); for (unsigned int x = 0; x < llcdissect_chain.size() && (pcl = llcdissect_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); for (unsigned int x = 0; x < decrypt_chain.size() && (pcl = decrypt_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); for (unsigned int x = 0; x < datadissect_chain.size() && (pcl = datadissect_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); for (unsigned int x = 0; x < classifier_chain.size() && (pcl = classifier_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); for (unsigned int x = 0; x < logging_chain.size() && (pcl = logging_chain[x]); x++) (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); DestroyPacket(in_pack); return 1; } void Packetchain::DestroyPacket(kis_packet *in_pack) { pc_link *pcl; // Push it through the destructors if there are any, we don't care // about error conditions for (unsigned int x = 0; x < destruction_chain.size(); x++) { pcl = destruction_chain[x]; (*(pcl->callback))(globalreg, pcl->auxdata, in_pack); } delete in_pack; } int Packetchain::RegisterHandler(pc_callback in_cb, void *in_aux, int in_chain, int in_prio) { pc_link *link = NULL; if (in_prio > 1000) { _MSG("Packetchain::RegisterHandler requested priority greater than 1000", MSGFLAG_ERROR); return -1; } // Generate packet, we'll nuke it if it's invalid later link = new pc_link; link->priority = in_prio; link->callback = in_cb; link->auxdata = in_aux; switch (in_chain) { case CHAINPOS_GENESIS: genesis_chain.push_back(link); stable_sort(genesis_chain.begin(), genesis_chain.end(), SortLinkPriority()); break; case CHAINPOS_POSTCAP: postcap_chain.push_back(link); stable_sort(postcap_chain.begin(), postcap_chain.end(), SortLinkPriority()); break; case CHAINPOS_LLCDISSECT: llcdissect_chain.push_back(link); stable_sort(llcdissect_chain.begin(), llcdissect_chain.end(), SortLinkPriority()); break; case CHAINPOS_DECRYPT: decrypt_chain.push_back(link); stable_sort(decrypt_chain.begin(), decrypt_chain.end(), SortLinkPriority()); break; case CHAINPOS_DATADISSECT: datadissect_chain.push_back(link); stable_sort(datadissect_chain.begin(), datadissect_chain.end(), SortLinkPriority()); break; case CHAINPOS_CLASSIFIER: classifier_chain.push_back(link); stable_sort(classifier_chain.begin(), classifier_chain.end(), SortLinkPriority()); break; case CHAINPOS_LOGGING: logging_chain.push_back(link); stable_sort(logging_chain.begin(), logging_chain.end(), SortLinkPriority()); break; case CHAINPOS_DESTROY: destruction_chain.push_back(link); stable_sort(destruction_chain.begin(), destruction_chain.end(), SortLinkPriority()); break; default: delete link; _MSG("Packetchain::RegisterHandler requested unknown chain", MSGFLAG_ERROR); return -1; } return 1; } int Packetchain::RemoveHandler(pc_callback in_cb, int in_chain) { unsigned int x; switch (in_chain) { case CHAINPOS_GENESIS: for (x = 0; x < genesis_chain.size(); x++) { if (genesis_chain[x]->callback == in_cb) { genesis_chain.erase(genesis_chain.begin() + x); } } break; case CHAINPOS_POSTCAP: for (x = 0; x < postcap_chain.size(); x++) { if (postcap_chain[x]->callback == in_cb) { postcap_chain.erase(postcap_chain.begin() + x); } } break; case CHAINPOS_LLCDISSECT: for (x = 0; x < llcdissect_chain.size(); x++) { if (llcdissect_chain[x]->callback == in_cb) { llcdissect_chain.erase(llcdissect_chain.begin() + x); } } break; case CHAINPOS_DECRYPT: for (x = 0; x < decrypt_chain.size(); x++) { if (decrypt_chain[x]->callback == in_cb) { decrypt_chain.erase(decrypt_chain.begin() + x); } } break; case CHAINPOS_DATADISSECT: for (x = 0; x < datadissect_chain.size(); x++) { if (datadissect_chain[x]->callback == in_cb) { datadissect_chain.erase(datadissect_chain.begin() + x); } } break; case CHAINPOS_CLASSIFIER: for (x = 0; x < classifier_chain.size(); x++) { if (classifier_chain[x]->callback == in_cb) { classifier_chain.erase(classifier_chain.begin() + x); } } break; case CHAINPOS_LOGGING: for (x = 0; x < logging_chain.size(); x++) { if (logging_chain[x]->callback == in_cb) { logging_chain.erase(logging_chain.begin() + x); } } break; case CHAINPOS_DESTROY: for (x = 0; x < destruction_chain.size(); x++) { if (destruction_chain[x]->callback == in_cb) { destruction_chain.erase(destruction_chain.begin() + x); } } break; default: _MSG("Packetchain::RemoveHandler requested unknown chain", MSGFLAG_ERROR); return -1; } return 1; } kismet-2013-03-R1b/kis_panel_network.cc0000664000175000017500000036021612124602454017510 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "kis_panel_network.h" #include "kis_panel_windows.h" #include "kis_panel_frontend.h" #include "kis_panel_sort.h" #include "soundcontrol.h" const common_col_pref bssid_column_details[] = { { "decay", "Recent activity", bcol_decay }, { "name", "Name or SSID", bcol_name }, { "shortname", "Shortened name or SSID", bcol_shortname }, { "nettype", "Type of network", bcol_nettype }, { "crypt", "Encryption options", bcol_crypt }, { "channel", "Channel", bcol_channel }, { "packets", "Total packets", bcol_packets }, { "packdata", "Number of data packets", bcol_packdata }, { "packllc", "Number of LLC/Management packets", bcol_packllc }, { "packcrypt", "Number of encrypted data packets", bcol_packcrypt }, { "bssid", "BSSID", bcol_bssid }, { "clients", "Number of associated clients", bcol_clients }, { "datasize", "Amount of data seen", bcol_datasize }, { "beaconperc", "Percentage of expected beacons seen", bcol_beaconperc }, { "signal_dbm", "Signal (in dBm, depends on source", bcol_signal_dbm }, { "signal_rssi", "Signal (in RSSI, depends on source", bcol_signal_rssi }, { "freq_mhz", "Frequency (MHz)", bcol_freq_mhz }, { "manuf", "Manufacturer", bcol_manuf }, { "11dcountry", "802.11d Country", bcol_11dcountry }, { "seenby", "Sources that have seen this network", bcol_seenby }, { "ip", "Best-guess IP subnet", bcol_ip }, { "iprange", "Best-guess IP subnet + netmask", bcol_iprange }, { NULL, NULL, 0 } }; const char *Kis_Netlist::bssid_columns_text[] = { "decay", "name", "shortname", "nettype", "crypt", "channel", "packdata", "packllc", "packcrypt", "bssid", "packets", "clients", "datasize", "signalbar", "beaconperc", "signal_dbm", "signal_rssi", "freq_mhz", "11dcountry", NULL }; const common_col_pref bssid_extras_details[] = { { "lastseen", "Last seen timestamp", bext_lastseen }, { "bssid", "BSSID", bext_bssid }, { "crypt", "Encryption types", bext_crypt }, { "ip", "IP Address Guess", bext_ip }, { "manuf", "Manufacturer info", bext_manuf }, { "seenby", "Sources that have seen this network", bext_seenby }, { NULL, NULL} }; const char *bssid_fields[] = { "bssid", "type", "llcpackets", "datapackets", "cryptpackets", "channel", "firsttime", "lasttime", "atype", "rangeip", "netmaskip", "gatewayip", "gpsfixed", "minlat", "minlon", "minalt", "minspd", "maxlat", "maxlon", "maxalt", "maxspd", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", "bestlat", "bestlon", "bestalt", "agglat", "agglon", "aggalt", "aggpoints", "datasize", "turbocellnid", "turbocellmode", "turbocellsat", "carrierset", "maxseenrate", "encodingset", "decrypted", "dupeivpackets", "bsstimestamp", "cdpdevice", "cdpport", "fragments", "retries", "newpackets", "freqmhz", "manuf", "datacryptset", NULL }; const char *ssid_fields[] = { "mac", "checksum", "type", "ssid", "beaconinfo", "cryptset", "cloaked", "firsttime", "lasttime", "maxrate", "beaconrate", "packets", "beacons", "dot11d", NULL }; const char *client_fields[] = { "bssid", "mac", "type", "firsttime", "lasttime", "llcpackets", "datapackets", "cryptpackets", "signal_dbm", "noise_dbm", "minsignal_dbm", "minnoise_dbm", "maxsignal_dbm", "maxnoise_dbm", "signal_rssi", "noise_rssi", "minsignal_rssi", "minnoise_rssi", "maxsignal_rssi", "maxnoise_rssi", "gpsfixed", "bestlat", "bestlon", "bestalt", "agglat", "agglon", "aggalt", "aggpoints", "minlat", "minlon", "minalt", "maxlat", "maxlon", "maxalt", "atype", "ip", "gatewayip", "datasize", "maxseenrate", "encodingset", "carrierset", "decrypted", "channel", "fragments", "retries", "newpackets", "freqmhz", "cdpdevice", "cdpport", "manuf", "dhcphost", "dhcpvendor", "datacryptset", NULL }; const char *bssidsrc_fields[] = { "bssid", "uuid", "lasttime", "numpackets", NULL }; const char *clisrc_fields[] = { "bssid", "mac", "uuid", "lasttime", "numpackets", NULL }; const char *time_fields[] = { "timesec", NULL }; const char *info_fields[] = { "networks", "packets", "rate", "filtered", NULL }; // Netgroup management Kis_Display_NetGroup::Kis_Display_NetGroup() { local_metanet = 0; metanet = NULL; dirty = 0; dispdirty = 0; linecache = ""; expanded = 0; color = -1; } Kis_Display_NetGroup::Kis_Display_NetGroup(Netracker::tracked_network *in_net) { local_metanet = 0; metanet = in_net; meta_vec.push_back(in_net); dirty = 0; expanded = 0; ClearSetDirty(); in_net->groupptr = this; } Kis_Display_NetGroup::~Kis_Display_NetGroup() { // Only delete the metanet if it's a local construct if (local_metanet) { delete metanet; metanet = NULL; } } void Kis_Display_NetGroup::ClearSetDirty() { dispdirty = 1; linecache = ""; detcache.clear(); grpcache.clear(); } // Update merged network // // meta Group will not have update map of clients since they can collide between networks void Kis_Display_NetGroup::Update() { if (dirty == 0) return; // Shortcut stripping the last network. This ought to only happen // to the autogroup nets but its possible it will occur in other situations if (meta_vec.size() == 0) { if (local_metanet) delete metanet; metanet = NULL; dirty = 0; return; } ClearSetDirty(); // if we've gained networks and don't have a local metanet, we // just gained one. if (meta_vec.size() > 1 && local_metanet == 0) { local_metanet = 1; metanet = new Netracker::tracked_network; } // If we don't have a local meta network, just bail, because the // network we present is the same as the tcp network. if (local_metanet == 0) { // We're not dirty, the comprising network isn't dirty, we're // done here. dirty = 0; if (metanet != NULL) metanet->dirty = 0; return; } int first = 1; for (unsigned int x = 0; x < meta_vec.size(); x++) { Netracker::tracked_network *mv = meta_vec[x]; if (first) { metanet->bssid = mv->bssid; metanet->manuf = mv->manuf; metanet->type = mv->type; metanet->llc_packets = mv->llc_packets; metanet->data_packets = mv->data_packets; metanet->crypt_packets = mv->crypt_packets; metanet->channel = 0; // Merge the frequency counts for everything for (map::const_iterator fmi = mv->freq_mhz_map.begin(); fmi != mv->freq_mhz_map.end(); ++fmi) { if (metanet->freq_mhz_map.find(fmi->first) != metanet->freq_mhz_map.end()) metanet->freq_mhz_map[fmi->first] += fmi->second; else metanet->freq_mhz_map[fmi->first] = fmi->second; } metanet->last_time = mv->last_time; metanet->first_time = mv->first_time; metanet->decrypted = mv->decrypted; metanet->gpsdata = mv->gpsdata; metanet->snrdata = mv->snrdata; metanet->guess_ipdata = mv->guess_ipdata; metanet->client_disconnects = mv->client_disconnects; metanet->last_sequence = 0; metanet->bss_timestamp = 0; metanet->datasize = mv->datasize; metanet->dupeiv_packets = mv->dupeiv_packets; metanet->fragments = mv->fragments; metanet->retries = mv->retries; metanet->new_packets = mv->new_packets; metanet->ssid_map = mv->ssid_map; metanet->lastssid = mv->lastssid; first = 0; } else { // Compare the OUIs for manuf if (metanet->bssid.OUI() != mv->bssid.OUI()) metanet->manuf = "Mixed"; // Mask the BSSIDs metanet->bssid.longmac &= mv->bssid.longmac; if (metanet->type != mv->type) metanet->type = network_mixed; metanet->llc_packets += mv->llc_packets; metanet->data_packets += mv->data_packets; metanet->crypt_packets += mv->crypt_packets; if (mv->first_time < metanet->first_time) metanet->first_time = mv->first_time; if (mv->last_time > metanet->last_time) metanet->last_time = mv->last_time; metanet->decrypted += mv->decrypted; // Mmm overloaded metanet->gpsdata += mv->gpsdata; metanet->snrdata += mv->snrdata; // metanet->guess_ipdata += mv->guess_ipdata; metanet->client_disconnects += mv->client_disconnects; metanet->datasize += mv->datasize; metanet->fragments += mv->fragments; metanet->retries += mv->retries; metanet->new_packets += mv->new_packets; if (mv->lastssid != NULL) { if (metanet->lastssid == NULL) metanet->lastssid = mv->lastssid; else if (mv->lastssid->last_time > metanet->lastssid->last_time) metanet->lastssid = mv->lastssid; } else { metanet->lastssid = NULL; } // We don't combine CDP data } // The net is no longer dirty mv->dirty = 0; } if (metanet == NULL) dispdirty = 0; dirty = 0; } string Kis_Display_NetGroup::GetName() { return GetName(metanet); } string Kis_Display_NetGroup::GetName(Netracker::tracked_network *net) { int usenet = 1; if (net == NULL) { if (name != "") return name; net = metanet; usenet = 0; } if (net != NULL && (usenet || name == "")) { Netracker::adv_ssid_data *ssid = net->lastssid; // Return a sanely constructed name if we don't have any if (ssid == NULL || (ssid != NULL && ssid->ssid.length() == 0 && net->ssid_map.size() == 1)) { if (net->type == network_probe) return ""; else if (net->type == network_data) return ""; else return ""; } // If the map only has 2 items, and one of them is cloaked, then // display it with a "decloaked" identifier if (net->ssid_map.size() == 2) { int cloaked = -1; string clear; for (map::iterator i = net->ssid_map.begin(); i != net->ssid_map.end(); ++i) { if (i->second->ssid_cloaked) cloaked = 1; else clear = i->second->ssid; } if (cloaked == 1 && clear.length() > 0 && net->type != network_probe) { return string("<") + clear + string(">"); } else if (clear.length() > 0) { return clear; } } /* If the last one we found was clean, return that */ if (net->lastssid->ssid.length() > 0) return net->lastssid->ssid; /* Find a clear one */ for (map::iterator i = net->ssid_map.begin(); i != net->ssid_map.end(); ++i) { if (i->second->ssid_cloaked) continue; else return i->second->ssid; } return ""; } else { if (name == "") { return ""; } return name; } return ""; } void Kis_Display_NetGroup::SetName(string in_name) { name = in_name; ClearSetDirty(); } Netracker::tracked_network *Kis_Display_NetGroup::FetchNetwork() { return metanet; } void Kis_Display_NetGroup::AddNetwork(Netracker::tracked_network *in_net) { // Assume they won't call us without checking an external map // so this net isn't attached to any other groups // // Otherwise, adding a network is really simple, we just stick // it in the vec and flag dirty, more fun happens during the update meta_vec.push_back(in_net); in_net->groupptr = this; dirty = 1; ClearSetDirty(); } void Kis_Display_NetGroup::DelNetwork(Netracker::tracked_network *in_net) { // Maybe we need to replace this in the future if we do a lot of removal, // but on the assumption that most removal will really be destruction of // the entire network, we'll just do a linear search for (unsigned int x = 0; x < meta_vec.size(); x++) { if (meta_vec[x] == in_net) { meta_vec.erase(meta_vec.begin() + x); dirty = 1; break; } } in_net->groupptr = NULL; } void Kis_Display_NetGroup::DirtyNetwork(Netracker::tracked_network *in_net) { // No real reason to take a network, at the moment, but why not dirty = 1; } // Callbacks into the classes proper void KisNetlist_Configured(CLICONF_CB_PARMS) { ((Kis_Netlist *) auxptr)->NetClientConfigure(kcli, recon); } void KisNetlist_AddCli(KPI_ADDCLI_CB_PARMS) { ((Kis_Netlist *) auxptr)->NetClientAdd(netcli, add); } void KisNetlist_BSSID(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_BSSID(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_SSID(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_SSID(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_CLIENT(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_CLIENT(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_NETTAG(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_NETTAG(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_CLITAG(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_CLITAG(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_BSSIDSRC(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_BSSIDSRC(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisNetlist_CLISRC(CLIPROTO_CB_PARMS) { ((Kis_Netlist *) auxptr)->Proto_CLISRC(globalreg, proto_string, proto_parsed, srccli, auxptr); } // Event callbacks int Event_Netlist_Update(TIMEEVENT_PARMS) { ((Kis_Netlist *) parm)->UpdateTrigger(); return 1; } Kis_Netlist::Kis_Netlist(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { kpinterface = in_panel->FetchPanelInterface(); // Zero the dirty timestamp bcol_pref_t = bext_pref_t = sort_pref_t = 0; viewable_lines = 0; viewable_cols = 0; sort_mode = netsort_autofit; updateref = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &Event_Netlist_Update, (void *) this); hpos = 0; selected_line = -1; first_line = 0; last_line = 0; probe_autogroup = adhoc_autogroup = data_autogroup = NULL; for (int x = 0; x < kis_netlist_color_max; x++) color_map[x] = 0; color_inactive = 0; // Assemble our protocol lines asm_bssid_num = TokenNullJoin(&asm_bssid_fields, bssid_fields); asm_ssid_num = TokenNullJoin(&asm_ssid_fields, ssid_fields); asm_client_num = TokenNullJoin(&asm_client_fields, client_fields); asm_bssidsrc_num = TokenNullJoin(&asm_bssidsrc_fields, bssidsrc_fields); asm_clisrc_num = TokenNullJoin(&asm_clisrc_fields, clisrc_fields); draw_vec = &display_vec; filter_dirty = 0; last_mouse_click = 0; // Set default preferences for BSSID columns if we don't have any in the // preferences file, then update the column vector UpdateBColPrefs(); UpdateBExtPrefs(); UpdateSortPrefs(); addref = kpinterface->Add_NetCli_AddCli_CB(KisNetlist_AddCli, (void *) this); } Kis_Netlist::~Kis_Netlist() { // Remove the callback kpinterface->Remove_Netcli_AddCli_CB(addref); kpinterface->Remove_All_Netcli_Conf_CB(KisNetlist_Configured); // Remove the callback the hard way from anyone still using it kpinterface->Remove_All_Netcli_ProtoHandler("BSSID", KisNetlist_BSSID, this); kpinterface->Remove_All_Netcli_ProtoHandler("SSID", KisNetlist_SSID, this); kpinterface->Remove_All_Netcli_ProtoHandler("CLIENT", KisNetlist_CLIENT, this); kpinterface->Remove_All_Netcli_ProtoHandler("BSSIDSRC", KisNetlist_BSSIDSRC, this); kpinterface->Remove_All_Netcli_ProtoHandler("CLISRC", KisNetlist_CLISRC, this); kpinterface->Remove_All_Netcli_ProtoHandler("NETTAG", KisNetlist_NETTAG, this); kpinterface->Remove_All_Netcli_ProtoHandler("CLITAG", KisNetlist_CLITAG, this); // Remove the timer globalreg->timetracker->RemoveTimer(updateref); // TODO - clean up the display vector incase for some reason we're being // destroyed without exiting the program } int Kis_Netlist::UpdateBColPrefs() { string pcols; // Use a default set of columns if we don't find one if ((pcols = kpinterface->prefs->FetchOpt("NETLIST_COLUMNS")) == "") { pcols = "decay,name,nettype,crypt,channel,packets,datasize"; kpinterface->prefs->SetOpt("NETLIST_COLUMNS", pcols, time(0)); } if (kpinterface->prefs->FetchOptDirty("NETLIST_COLUMNS") == bcol_pref_t && display_bcols.size() != 0) return 0; bcol_pref_t = kpinterface->prefs->FetchOptDirty("NETLIST_COLUMNS"); display_bcols.clear(); vector toks = StrTokenize(pcols, ","); string t; // Clear the cached headers colhdr_cache = ""; for (unsigned int x = 0; x < toks.size(); x++) { t = StrLower(toks[x]); int set = 0; for (unsigned int y = 0; bssid_column_details[y].pref != NULL; y++) { if (t == StrLower(bssid_column_details[y].pref)) { display_bcols.push_back((bssid_columns) bssid_column_details[y].ref); set = 1; break; } } if (set == 0) _MSG("Unknown display column '" + t + "', skipping.", MSGFLAG_INFO); } for (unsigned int x = 0; x < draw_vec->size(); x++) { (*draw_vec)[x]->SetDispDirty(1); } return 1; } int Kis_Netlist::UpdateBExtPrefs() { string pcols; // Use a default set of columns if we don't find one if ((pcols = kpinterface->prefs->FetchOpt("NETLIST_EXTRAS")) == "") { pcols = "bssid,lastseen,crypt,ip,manuf"; kpinterface->prefs->SetOpt("NETLIST_EXTRAS", pcols, time(0)); } if (kpinterface->prefs->FetchOptDirty("NETLIST_EXTRAS") == bext_pref_t && display_bexts.size() != 0) return 0; bext_pref_t = kpinterface->prefs->FetchOptDirty("NETLIST_EXTRAS"); display_bexts.clear(); vector toks = StrTokenize(pcols, ","); string t; for (unsigned int x = 0; x < toks.size(); x++) { t = StrLower(toks[x]); int set = 0; for (unsigned int y = 0; bssid_extras_details[y].pref != NULL; y++) { if (t == StrLower(bssid_extras_details[y].pref)) { display_bexts.push_back((bssid_extras) bssid_extras_details[y].ref); set = 1; break; } } if (set == 0) _MSG("Unknown display extra field '" + t + "', skipping.", MSGFLAG_INFO); } return 1; } int Kis_Netlist::UpdateSortPrefs() { string sort; // Use a default set of columns if we don't find one if ((sort = kpinterface->prefs->FetchOpt("NETLIST_SORT")) == "") { sort = "auto"; kpinterface->prefs->SetOpt("NETLIST_SORT", sort, time(0)); } if (kpinterface->prefs->FetchOptDirty("NETLIST_SORT") == sort_pref_t) return 0; sort_pref_t = kpinterface->prefs->FetchOptDirty("NETLIST_SORT"); sort = StrLower(sort); if (sort == "auto") sort_mode = netsort_autofit; else if (sort == "type") sort_mode = netsort_type; else if (sort == "channel") sort_mode = netsort_channel; else if (sort == "first") sort_mode = netsort_first; else if (sort == "first_desc") sort_mode = netsort_first_desc; else if (sort == "last") sort_mode = netsort_last; else if (sort == "last_desc") sort_mode = netsort_last_desc; else if (sort == "bssid") sort_mode = netsort_bssid; else if (sort == "ssid") sort_mode = netsort_ssid; else if (sort == "packets") sort_mode = netsort_packets; else if (sort == "signal") sort_mode = netsort_sdbm; else if (sort == "packets_desc") sort_mode = netsort_packets_desc; else if (sort == "crypt_type") sort_mode = netsort_crypt; else sort_mode = netsort_autofit; return 1; } void Kis_Netlist::NetClientConfigure(KisNetClient *in_cli, int in_recon) { void (*null_proto)(CLIPROTO_CB_PARMS) = NULL; for (macmap::iterator x = bssid_raw_map.begin(); x != bssid_raw_map.end(); ++x) { // Ugly hack to deal with "broken" macmap iterators which are really pointers delete *(x->second); } bssid_raw_map.clear(); dirty_raw_vec.clear(); for (unsigned int x = 0; x < display_vec.size(); x++) { delete display_vec[x]; } display_vec.clear(); filter_display_vec.clear(); netgroup_asm_map.clear(); probe_autogroup = NULL; adhoc_autogroup = NULL; data_autogroup = NULL; if (in_cli->RegisterProtoHandler("NETWORK", "*", null_proto, this) >= 0) { _MSG("This looks like an old kismet-stable server, the Kismet-newcore " "client can only talk to Kismet-newcore servers, connection will " "be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } // Register these first so we get the first pass of data when the network // populates if (in_cli->RegisterProtoHandler("BSSIDSRC", asm_bssidsrc_fields, KisNetlist_BSSIDSRC, this) < 0) { _MSG("Could not register BSSIDSRC protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } if (in_cli->RegisterProtoHandler("CLISRC", asm_clisrc_fields, KisNetlist_CLISRC, this) < 0) { _MSG("Could not register BSSIDSRC protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } if (in_cli->RegisterProtoHandler("BSSID", asm_bssid_fields, KisNetlist_BSSID, this) < 0) { _MSG("Could not register BSSID protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } if (in_cli->RegisterProtoHandler("SSID", asm_ssid_fields, KisNetlist_SSID, this) < 0) { _MSG("Could not register SSID protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } if (in_cli->RegisterProtoHandler("NETTAG", "bssid,tag,value", KisNetlist_NETTAG, this) < 0) { _MSG("Could not register NETTAG protocol with remote server", MSGFLAG_ERROR); } if (in_cli->RegisterProtoHandler("CLITAG", "bssid,mac,tag,value", KisNetlist_CLITAG, this) < 0) { _MSG("Could not register CLITAG protocol with remote server", MSGFLAG_ERROR); } if (in_cli->RegisterProtoHandler("CLIENT", asm_client_fields, KisNetlist_CLIENT, this) < 0) { _MSG("Could not register CLIENT protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); return; } } void Kis_Netlist::NetClientAdd(KisNetClient *in_cli, int add) { if (add == 0) { // Ignore remove events for now return; } // Add a client configured callback to the new client so we can load // our protocols in_cli->AddConfCallback(KisNetlist_Configured, 1, this); } void Kis_Netlist::SetFilter(vector filter, int display_only) { filter_vec = filter; display_filter_only = display_only; filter_dirty = 1; filter_display_vec.clear(); // Reset the vector we render if we have a filter if (filter_vec.size() != 0) draw_vec = &filter_display_vec; else draw_vec = &display_vec; UpdateTrigger(); } void Kis_Netlist::SetPosition(int isx, int isy, int iex, int iey) { Kis_Panel_Component::SetPosition(isx, isy, iex, iey); viewable_lines = ly - 1; viewable_cols = ex; } void Kis_Netlist::Proto_BSSID(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_bssid_num) { return; } int fnum = 0; Netracker::tracked_network *net = new Netracker::tracked_network; int tint; float tfloat; long double tlf; long long unsigned int tlld; mac_addr tmac; // BSSID tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete net; return; } net->bssid = tmac; // Type if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete net; return; } net->type = (network_type) tint; // Packet counts if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->llc_packets)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->data_packets)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->crypt_packets)) != 1) { delete net; return; } // Channel if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->channel)) != 1) { delete net; return; } // Times if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete net; return; } net->first_time = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete net; return; } net->last_time = tint; // Atype if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete net; return; } net->guess_ipdata.ip_type = (kis_ipdata_type) tint; // Rangeip if (inet_aton((*proto_parsed)[fnum++].word.c_str(), &(net->guess_ipdata.ip_addr_block)) == 0) { delete net; return; } // Maskip if (inet_aton((*proto_parsed)[fnum++].word.c_str(), &(net->guess_ipdata.ip_netmask)) == 0) { delete net; return; } // Gateip if (inet_aton((*proto_parsed)[fnum++].word.c_str(), &(net->guess_ipdata.ip_gateway)) == 0) { delete net; return; } // GPS if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->gpsdata.gps_valid)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.min_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.min_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.min_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.min_spd = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.max_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.max_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.max_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->gpsdata.max_spd = tfloat; // Signal levels if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.last_signal_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.last_noise_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.min_signal_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.min_noise_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.max_signal_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.max_noise_dbm)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.last_signal_rssi)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.last_noise_rssi)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.min_signal_rssi)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.min_noise_rssi)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.max_signal_rssi)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.max_noise_rssi)) != 1) { delete net; return; } // SNR lat/lon if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->snrdata.peak_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->snrdata.peak_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete net; return; } net->snrdata.peak_alt = tfloat; // gpsdata aggregates if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete net; return; } net->gpsdata.aggregate_lat = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete net; return; } net->gpsdata.aggregate_lon = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete net; return; } net->gpsdata.aggregate_alt = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%ld", &(net->gpsdata.aggregate_points)) != 1) { delete net; return; } // Data size if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%llu", &tlld) != 1) { delete net; return; } net->datasize = tlld; // We don't handle turbocell yet, so ignore it // 35 tcnid // 36 tcmode // 37 tcsat fnum += 3; // SNR carrierset if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.carrierset)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.maxseenrate)) != 1) { delete net; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->snrdata.encodingset)) != 1) { delete net; return; } // Decrypted if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->decrypted)) != 1) { delete net; return; } // Dupeiv if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->dupeiv_packets)) != 1) { delete net; return; } // BSS time stamp if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%llu", &tlld) != 1) { delete net; return; } net->bss_timestamp = tlld; // CDP data net->cdp_dev_id = MungeToPrintable((*proto_parsed)[fnum++].word); net->cdp_port_id = MungeToPrintable((*proto_parsed)[fnum++].word); if (net->cdp_dev_id == " ") net->cdp_dev_id = ""; if (net->cdp_port_id == " ") net->cdp_port_id = ""; // Fragments if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->fragments)) != 1) { delete net; return; } // Retries if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->retries)) != 1) { delete net; return; } // New packets if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->new_packets)) != 1) { delete net; return; } // Frequency packed field vector freqtoks = StrTokenize((*proto_parsed)[fnum++].word, "*"); for (unsigned int fi = 0; fi < freqtoks.size(); fi++) { unsigned int freq, count; // Just ignore parse errors if (sscanf(freqtoks[fi].c_str(), "%u:%u", &freq, &count) != 2) continue; net->freq_mhz_map[freq] = count; } // Manuf field net->manuf = MungeToPrintable((*proto_parsed)[fnum++].word); if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%llu", &tlld) != 1) { delete net; return; } net->data_cryptset = tlld; /* if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(net->freq_mhz)) != 1) { delete net; return; } */ // Determine if we're going to just merge data with the old network, and then // determine what we have to do for repositioning the record in the viewable // list macmap::iterator ti = bssid_raw_map.find(net->bssid); if (ti == bssid_raw_map.end()) { // Flag dirty, add to vector, we'll deal with it later net->dirty = 1; dirty_raw_vec.push_back(net); bssid_raw_map.insert(net->bssid, net); return; } Netracker::tracked_network *onet = *(ti->second); // Merge the new data into the old data onet->type = net->type; onet->llc_packets = net->llc_packets; onet->data_packets = net->data_packets; onet->crypt_packets = net->crypt_packets; onet->channel = net->channel; onet->freq_mhz_map = net->freq_mhz_map; onet->last_time = net->last_time; onet->decrypted = net->decrypted; onet->client_disconnects = net->client_disconnects; onet->last_sequence = net->last_sequence; onet->bss_timestamp = net->bss_timestamp; onet->datasize = net->datasize; onet->dupeiv_packets = net->dupeiv_packets; onet->fragments = net->fragments; onet->retries = net->retries; onet->new_packets = net->new_packets; onet->snrdata = net->snrdata; onet->gpsdata = net->gpsdata; onet->manuf = net->manuf; onet->data_cryptset = net->data_cryptset; delete net; // Push a dirty net into the vec, collapse multiple updates to a // net within a single draw update by not pushing already dirty data if (onet->dirty == 0) { onet->dirty = 1; dirty_raw_vec.push_back(onet); } return; } void Kis_Netlist::Proto_SSID(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_ssid_num) { return; } int fnum = 0; Netracker::adv_ssid_data *asd = new Netracker::adv_ssid_data; Netracker::tracked_network *net = NULL; int tint; float tfloat; mac_addr tmac; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete asd; return; } // Try to find the network this belongs to, if for some reason we don't have // a record of it, throw it out and stop processing macmap::iterator tni = bssid_raw_map.find(tmac); if (tni == bssid_raw_map.end()) { delete asd; return; } net = *(tni->second); asd->mac = tmac; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->checksum = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->type = (ssid_type) tint; asd->ssid = MungeToPrintable((*proto_parsed)[fnum++].word); asd->beacon_info = MungeToPrintable((*proto_parsed)[fnum++].word); if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->cryptset = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->ssid_cloaked = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->first_time = (time_t) tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->last_time = (time_t) tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete asd; return; } asd->maxrate = (double) tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->beaconrate = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->packets = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete asd; return; } asd->beacons = tint; vector dot11d = StrTokenize((*proto_parsed)[fnum++].word, ":"); if (dot11d.size() >= 2) { asd->dot11d_country = MungeToPrintable(dot11d[0]); for (unsigned int x = 1; x < dot11d.size(); x++) { dot11d_range_info ri; if (sscanf(dot11d[x].c_str(), "%u-%u-%u", &(ri.startchan), &(ri.numchan), &(ri.txpower)) != 3) { delete asd; return; } asd->dot11d_vec.push_back(ri); } } map::iterator asi = net->ssid_map.find(asd->checksum); // Just add us if we don't exist in the network map if (asi == net->ssid_map.end()) { asd->dirty = 1; net->ssid_map[asd->checksum] = asd; net->lastssid = asd; vector spktxt; spktxt.push_back(asd->ssid == "" ? "unknown" : asd->ssid); spktxt[0] = globalreg->soundctl->EncodeSpeechString(spktxt[0]); spktxt.push_back(IntToString(net->channel)); spktxt.push_back(net->bssid.Mac2String()); kpinterface->FetchMainPanel()->SpeakString("new", spktxt); } else { // Otherwise we need to copy all our stuff into the existing record Netracker::adv_ssid_data *oasd = asi->second; *oasd = *asd; net->lastssid = oasd; delete asd; } // Set the net dirty and push it into the dirty vec if it isn't there already if (net->dirty == 0) { net->dirty = 1; dirty_raw_vec.push_back(net); } return; } void Kis_Netlist::Proto_CLIENT(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_client_num) { return; } int fnum = 0; Netracker::tracked_client *cli = new Netracker::tracked_client; Netracker::tracked_network *pnet = NULL; int tint; float tfloat; long double tlf; long long unsigned int tlld; mac_addr tmac; // BSSID tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete cli; return; } // Reject if we don't know the network if (bssid_raw_map.find(tmac) == bssid_raw_map.end()) { delete cli; return; } pnet = bssid_raw_map[tmac]; cli->bssid = tmac; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete cli; return; } cli->mac = tmac; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete cli; return; } cli->type = (client_type) tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete cli; return; } cli->first_time = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete cli; return; } cli->last_time = tint; // Packet counts if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->llc_packets)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->data_packets)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->crypt_packets)) != 1) { delete cli; return; } // Signal levels if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.last_signal_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.last_noise_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.min_signal_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.min_noise_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.max_signal_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.max_noise_dbm)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.last_signal_rssi)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.last_noise_rssi)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.min_signal_rssi)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.min_noise_rssi)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.max_signal_rssi)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.max_noise_rssi)) != 1) { delete cli; return; } // GPS if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->gpsdata.gps_valid)) != 1) { delete cli; return; } // SNR lat/lon if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->snrdata.peak_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->snrdata.peak_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->snrdata.peak_alt = tfloat; // gpsdata aggregates if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete cli; return; } cli->gpsdata.aggregate_lat = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete cli; return; } cli->gpsdata.aggregate_lon = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%Lf", &tlf) != 1) { delete cli; return; } cli->gpsdata.aggregate_alt = tlf; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%ld", &(cli->gpsdata.aggregate_points)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.min_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.min_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.min_alt = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.max_lat = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.max_lon = tfloat; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%f", &tfloat) != 1) { delete cli; return; } cli->gpsdata.max_alt = tfloat; // Atype if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete cli; return; } cli->guess_ipdata.ip_type = (kis_ipdata_type) tint; // Rangeip if (inet_aton((*proto_parsed)[fnum++].word.c_str(), &(cli->guess_ipdata.ip_addr_block)) == 0) { delete cli; return; } // Gateip if (inet_aton((*proto_parsed)[fnum++].word.c_str(), &(cli->guess_ipdata.ip_gateway)) == 0) { delete cli; return; } // Data size if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%llu", &tlld) != 1) { delete cli; return; } cli->datasize = tlld; // SNR carrierset if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.maxseenrate)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.encodingset)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->snrdata.carrierset)) != 1) { delete cli; return; } // Decrypted if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->decrypted)) != 1) { delete cli; return; } if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->channel)) != 1) { delete cli; return; } // Fragments if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->fragments)) != 1) { delete cli; return; } // Retries if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->retries)) != 1) { delete cli; return; } // New packets if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &(cli->new_packets)) != 1) { delete cli; return; } // Frequency packed field vector freqtoks = StrTokenize((*proto_parsed)[fnum++].word, "*"); for (unsigned int fi = 0; fi < freqtoks.size(); fi++) { unsigned int freq, count; // Just ignore parse errors if (sscanf(freqtoks[fi].c_str(), "%u:%u", &freq, &count) != 2) continue; cli->freq_mhz_map[freq] = count; } // CDP data cli->cdp_dev_id = MungeToPrintable((*proto_parsed)[fnum++].word); cli->cdp_port_id = MungeToPrintable((*proto_parsed)[fnum++].word); if (cli->cdp_dev_id == " ") cli->cdp_dev_id = ""; if (cli->cdp_port_id == " ") cli->cdp_port_id = ""; // manuf cli->manuf = MungeToPrintable((*proto_parsed)[fnum++].word); cli->dhcp_host = MungeToPrintable((*proto_parsed)[fnum++].word); cli->dhcp_vendor = MungeToPrintable((*proto_parsed)[fnum++].word); if (cli->dhcp_host == " ") cli->dhcp_host = ""; if (cli->dhcp_vendor == " ") cli->dhcp_vendor = ""; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%llu", &tlld) != 1) { delete cli; return; } cli->data_cryptset = tlld; cli->dirty = 1; // Merge or new map::iterator ti = pnet->client_map.find(cli->mac); if (ti == pnet->client_map.end()) { // Flag dirty, add to vector, we'll deal with it later if (pnet->dirty == 0) { pnet->dirty = 1; dirty_raw_vec.push_back(pnet); } pnet->client_map.insert(make_pair(cli->mac, cli)); return; } Netracker::tracked_client *ocli = ti->second; // Merge the new data into the old data - don't replace the pointer since we have // other things referencing it ocli->type = cli->type; ocli->last_time = cli->last_time; ocli->decrypted = cli->decrypted; ocli->bssid = cli->bssid; ocli->channel = cli->channel; ocli->freq_mhz_map = cli->freq_mhz_map; ocli->llc_packets = cli->llc_packets; ocli->data_packets = cli->data_packets; ocli->crypt_packets = cli->crypt_packets; ocli->last_sequence = cli->last_sequence; ocli->datasize = cli->datasize; ocli->fragments = cli->fragments; ocli->retries = cli->retries; ocli->cdp_dev_id = cli->cdp_dev_id; ocli->cdp_port_id = cli->cdp_port_id; ocli->new_packets = cli->new_packets; ocli->guess_ipdata = cli->guess_ipdata; ocli->snrdata = cli->snrdata; ocli->gpsdata = cli->gpsdata; ocli->manuf = cli->manuf; ocli->netptr = pnet; ocli->data_cryptset = cli->data_cryptset; ocli->dirty = 1; delete cli; // We don't do anything as fancy with client dirty tracking since we'll only // be displaying them in sub-windows return; } void Kis_Netlist::Proto_BSSIDSRC(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_bssidsrc_num) { return; } int fnum = 0; int newsd = 0; Netracker::source_data *sd = NULL; Netracker::tracked_network *net = NULL; mac_addr tmac; unsigned int tint; uuid tuuid; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { return; } // Try to find the network this belongs to, if for some reason we don't have // a record of it, throw it out and stop processing macmap::iterator tni = bssid_raw_map.find(tmac); if (tni == bssid_raw_map.end()) { return; } net = *(tni->second); tuuid = uuid((*proto_parsed)[fnum++].word); if (tuuid.error) { return; } if (net->source_map.find(tuuid) == net->source_map.end()) { sd = new Netracker::source_data; newsd = 1; } else { sd = net->source_map[tuuid]; } sd->bssid = tmac; sd->source_uuid = tuuid; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tint) != 1) { delete sd; return; } sd->last_seen = (time_t) tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tint) != 1) { delete sd; return; } sd->num_packets = (time_t) tint; if (newsd) net->source_map[sd->source_uuid] = sd; return; } void Kis_Netlist::Proto_CLISRC(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_bssidsrc_num) { return; } int fnum = 0; int newsd = 0; Netracker::source_data *sd = NULL; Netracker::tracked_network *net = NULL; Netracker::tracked_client *cli = NULL; mac_addr tmac; unsigned int tint; uuid tuuid; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { return; } // Try to find the network this belongs to, if for some reason we don't have // a record of it, throw it out and stop processing macmap::iterator tni = bssid_raw_map.find(tmac); if (tni == bssid_raw_map.end()) { return; } net = *(tni->second); tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { return; } map::iterator ti = net->client_map.find(tmac); if (ti == net->client_map.end()) { return; } cli = ti->second; tuuid = uuid((*proto_parsed)[fnum++].word); if (tuuid.error) { return; } if (net->source_map.find(tuuid) == net->source_map.end()) { sd = new Netracker::source_data; newsd = 1; } else { sd = net->source_map[tuuid]; } sd->bssid = net->bssid; sd->mac = cli->mac; sd->source_uuid = tuuid; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tint) != 1) { delete sd; return; } sd->last_seen = (time_t) tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tint) != 1) { delete sd; return; } sd->num_packets = (time_t) tint; if (newsd) cli->source_map[sd->source_uuid] = sd; return; } void Kis_Netlist::Proto_NETTAG(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < 3) { return; } Netracker::tracked_network *net = NULL; mac_addr bssid = mac_addr((*proto_parsed)[0].word.c_str()); if (bssid.error) { return; } macmap::iterator tni = bssid_raw_map.find(bssid); if (tni == bssid_raw_map.end()) { return; } net = *(tni->second); net->arb_tag_map[MungeToPrintable((*proto_parsed)[1].word)] = MungeToPrintable((*proto_parsed)[2].word); // Set the net dirty and push it into the dirty vec if it isn't there already if (net->dirty == 0) { net->dirty = 1; dirty_raw_vec.push_back(net); } return; } void Kis_Netlist::Proto_CLITAG(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < 4) { return; } Netracker::tracked_network *net = NULL; Netracker::tracked_client *cli = NULL; mac_addr bssid = mac_addr((*proto_parsed)[0].word.c_str()); if (bssid.error) { return; } mac_addr mac = mac_addr((*proto_parsed)[1].word.c_str()); if (mac.error) { return; } macmap::iterator tni = bssid_raw_map.find(bssid); if (tni == bssid_raw_map.end()) { return; } net = *(tni->second); map::iterator tci = net->client_map.find(mac); if (tci == net->client_map.end()) { return; } cli = tci->second; cli->arb_tag_map[MungeToPrintable((*proto_parsed)[2].word)] = MungeToPrintable((*proto_parsed)[3].word); cli->dirty = 1; return; } int Kis_Netlist::DeleteGroup(Kis_Display_NetGroup *in_group) { for (unsigned int x = 0; x < display_vec.size(); x++) { if (display_vec[x] == in_group) { display_vec.erase(display_vec.begin() + x); break; } } for (unsigned int x = 0; x < filter_display_vec.size(); x++) { if (filter_display_vec[x] == in_group) { filter_display_vec.erase(filter_display_vec.begin() + x); break; } } vector *nv = in_group->FetchNetworkVec(); // Shift all the networks into the dirty vector, unlink them from the // additional group tracking methods for (unsigned int x = 0; x < nv->size(); x++) { (*nv)[x]->groupptr = NULL; if ((*nv)[x]->dirty == 0) { dirty_raw_vec.push_back((*nv)[x]); (*nv)[x]->dirty = 1; } if (netgroup_stored_map.find((*nv)[x]->bssid) != netgroup_stored_map.end()) netgroup_stored_map.erase((*nv)[x]->bssid); if (netgroup_asm_map.find((*nv)[x]->bssid) != netgroup_asm_map.end()) netgroup_asm_map.erase((*nv)[x]->bssid); } delete in_group; return 1; } void Kis_Netlist::UpdateTrigger(void) { // Use the same timer to update the source stuff from the info list // We'd normally do this somewhere else but since we own the infobits // segment we'll do it here // Process the dirty vector and update all our stuff. This only happens // at regular intervals, not every network update // This code exposes some nasty problems with the macmap iterators, // namely that they're always pointers no matter what. Some day, this // could get fixed. // Remember what we had selected Kis_Display_NetGroup *prev_sel = FetchSelectedNetgroup(); // If we've changed the filter, re-filter all the existing display stuff if (filter_dirty) { for (unsigned int x = 0; x < display_vec.size(); x++) { if (display_vec[x]->FetchNetwork() == NULL) continue; for (unsigned int y = 0; y < filter_vec.size(); y++) { if (filter_vec[y] == display_vec[x]->FetchNetwork()->bssid) { break; } } } filter_dirty = 0; } // Show extended info? if (kpinterface->prefs->FetchOpt("NETLIST_SHOWEXT") == "0") show_ext_info = 0; else show_ext_info = 1; if (UpdateSortPrefs() == 0 && dirty_raw_vec.size() == 0) return; vector dirty_vec; for (unsigned int x = 0; x < dirty_raw_vec.size(); x++) { Netracker::tracked_network *net = dirty_raw_vec[x]; net->dirty = 0; Kis_Display_NetGroup *dng = (Kis_Display_NetGroup *) net->groupptr; // Handle the autogrouping code if (net->type == network_probe) { // Delete it from any group its in already if (net->groupptr != probe_autogroup) { if (net->groupptr != NULL) { if (dng->Dirty() == 0) dirty_vec.push_back(dng); dng->DelNetwork(net); } } // Make the group if we need to, otherwise add to it if (probe_autogroup == NULL) { probe_autogroup = new Kis_Display_NetGroup(net); probe_autogroup->SetName("Autogroup Probe"); netgroup_asm_map.insert(net->bssid, probe_autogroup); display_vec.push_back(probe_autogroup); } else if (probe_autogroup != net->groupptr){ if (probe_autogroup->Dirty() == 0) dirty_vec.push_back(probe_autogroup); probe_autogroup->AddNetwork(net); } continue; } else if (net->type != network_probe && net->groupptr == probe_autogroup && net->groupptr != NULL) { if (probe_autogroup->Dirty() == 0) dirty_vec.push_back(probe_autogroup); probe_autogroup->DelNetwork(net); } if (net->type == network_adhoc) { if (net->groupptr != adhoc_autogroup) { if (net->groupptr != NULL) { if (dng->Dirty() == 0) dirty_vec.push_back(dng); dng->DelNetwork(net); } } if (adhoc_autogroup == NULL) { adhoc_autogroup = new Kis_Display_NetGroup(net); adhoc_autogroup->SetName("Autogroup Adhoc"); netgroup_asm_map.insert(net->bssid, adhoc_autogroup); display_vec.push_back(adhoc_autogroup); } else if (adhoc_autogroup != net->groupptr){ if (adhoc_autogroup->Dirty() == 0) dirty_vec.push_back(adhoc_autogroup); adhoc_autogroup->AddNetwork(net); } continue; } else if (net->type != network_adhoc && net->groupptr == adhoc_autogroup && net->groupptr != NULL) { if (adhoc_autogroup->Dirty() == 0) dirty_vec.push_back(adhoc_autogroup); adhoc_autogroup->DelNetwork(net); } if (net->type == network_data) { if (net->groupptr != data_autogroup) { if (net->groupptr != NULL) { if (dng->Dirty() == 0) dirty_vec.push_back(dng); dng->DelNetwork(net); } } if (data_autogroup == NULL) { data_autogroup = new Kis_Display_NetGroup(net); data_autogroup->SetName("Autogroup Data"); netgroup_asm_map.insert(net->bssid, data_autogroup); display_vec.push_back(data_autogroup); } else if (data_autogroup != net->groupptr){ if (data_autogroup->Dirty() == 0) dirty_vec.push_back(data_autogroup); data_autogroup->AddNetwork(net); } continue; } else if (net->type != network_data && net->groupptr == data_autogroup && net->groupptr != NULL) { if (data_autogroup->Dirty() == 0) dirty_vec.push_back(data_autogroup); data_autogroup->DelNetwork(net); } // Is it already assigned to a group? If it is, we can just // flag the display group as dirty and be done if (net->groupptr != NULL) { ((Kis_Display_NetGroup *) net->groupptr)->DirtyNetwork(net); ((Kis_Display_NetGroup *) net->groupptr)->Update(); continue; } // We have no group. That means we have to: // Be assigned to a group and that group updated, // Be assigned to a pre-defined group and that group updated, // or get a new group all our own Kis_Display_NetGroup *ng = NULL; macmap::iterator nsmi = netgroup_stored_map.find(net->bssid); // We don't belong to an existing network at all, make a new one if (nsmi == netgroup_stored_map.end()) { ng = new Kis_Display_NetGroup(net); netgroup_asm_map.insert(net->bssid, ng); // Add it to our filter vec for (unsigned int f = 0; f < filter_vec.size(); f++) { if (filter_vec[f] == net->bssid) { filter_display_vec.push_back(ng); break; } } // Add it to our normal display vec display_vec.push_back(ng); continue; } // We see if we're already allocated macmap::iterator nami = netgroup_asm_map.find(*(nsmi->second)); if (nami != netgroup_asm_map.end()) { // Assign before adding since adding makes it dirty if ((*(nami->second))->Dirty() == 0) dirty_vec.push_back(*(nami->second)); (*(nami->second))->AddNetwork(net); } else { // We need to make the group, add it to the allocation, then // add our network to it... it doesn't need to be added to the // dirty vector, because it gets linked instantly Kis_Display_NetGroup *ng = new Kis_Display_NetGroup(net); netgroup_asm_map.insert(*(nsmi->second), ng); // Add it to our filter vec for (unsigned int f = 0; f < filter_vec.size(); f++) { if (filter_vec[f] == *(nsmi->second)) { filter_display_vec.push_back(ng); break; } } display_vec.push_back(ng); } } // Update all the dirty groups (compress multiple active nets into a // single group update) int delnet = 0; for (unsigned int x = 0; x < dirty_vec.size(); x++) { dirty_vec[x]->Update(); if (dirty_vec[x]->FetchNumNetworks() == 0) { delnet |= DeleteGroup(dirty_vec[x]); // Update the autogroups if (dirty_vec[x] == probe_autogroup) probe_autogroup = NULL; else if (dirty_vec[x] == adhoc_autogroup) adhoc_autogroup = NULL; else if (dirty_vec[x] == data_autogroup) data_autogroup = NULL; } } // If we deleted a network, we need to re-run the trigger since we might // have disassembled groups if (delnet) { UpdateTrigger(); return; } // We've handled it all dirty_raw_vec.clear(); // Only sort the drawing vec, since it's the one we display switch (sort_mode) { case netsort_autofit: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_LastDesc()); break; case netsort_type: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Type()); break; case netsort_channel: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Channel()); break; case netsort_first: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_First()); break; case netsort_first_desc: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_FirstDesc()); break; case netsort_last: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Last()); break; case netsort_last_desc: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_LastDesc()); break; case netsort_bssid: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Bssid()); break; case netsort_ssid: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Ssid()); break; case netsort_sdbm: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Sdbm()); break; case netsort_packets: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Packets()); break; case netsort_packets_desc: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_PacketsDesc()); break; case netsort_crypt: stable_sort(draw_vec->begin(), draw_vec->end(), KisNetlist_Sort_Crypt()); default: break; } if (selected_line < (int) draw_vec->size() && selected_line >= 0 && (*draw_vec)[selected_line] != prev_sel) { // Remember what we had selected before for (unsigned int x = 0; x < draw_vec->size(); x++) { if (prev_sel == (*draw_vec)[x]) { if ((int) x <= viewable_lines) { // if the head of the list fits, fit it first_line = 0; selected_line = x; } else { // Otherwise scroll the top down to fit us int end_offt = draw_vec->size() - viewable_lines; if (end_offt > (int) x) { first_line = x - (viewable_lines / 2); selected_line = x; } else { first_line = draw_vec->size() - viewable_lines; selected_line = x; } } } } } } int Kis_Netlist::PrintNetworkLine(Kis_Display_NetGroup *ng, Netracker::tracked_network *net, int rofft, char *rline, int max) { // Are we using the passed net, or the derived meta? (for name fetching) int usenet = 1; Netracker::tracked_network *meta = ng->FetchNetwork(); if (meta == NULL) return rofft; if (net == NULL) { net = meta; usenet = 0; } map *cardmap = kpinterface->FetchNetCardMap(); map::iterator kci; for (unsigned c = 0; c < display_bcols.size(); c++) { bssid_columns b = display_bcols[c]; if (b == bcol_decay) { char d; int to; to = time(0) - net->last_time; if (to < 3) d = '!'; else if (to < 5) d = '.'; else d = ' '; snprintf(rline + rofft, max - rofft, "%c", d); rofft += 1; } else if (b == bcol_name) { string name; if (usenet) name = ng->GetName(net); else name = ng->GetName(NULL); snprintf(rline + rofft, max - rofft, "%-20.20s", name.c_str()); rofft += 20; } else if (b == bcol_shortname) { string name; if (usenet) name = ng->GetName(net); else name = ng->GetName(NULL); snprintf(rline + rofft, max - rofft, "%-10.10s", name.c_str()); rofft += 10; } else if (b == bcol_nettype) { char d; if (net->type == network_ap) d = 'A'; else if (net->type == network_adhoc) d = 'H'; else if (net->type == network_probe) d = 'P'; else if (net->type == network_turbocell) d = 'T'; else if (net->type == network_data) d = 'D'; else if (net->type == network_mixed) d = 'M'; else d = '?'; snprintf(rline + rofft, max - rofft, "%c", d); rofft += 1; } else if (b == bcol_crypt) { char d; if (net->lastssid == NULL) { d = '?'; } else { if (net->lastssid->cryptset == crypt_wep || (net->lastssid->cryptset & crypt_wpa_migmode)) d = 'W'; else if (net->lastssid->cryptset) d = 'O'; else d = 'N'; } snprintf(rline + rofft, max - rofft, "%c", d); rofft += 1; } else if (b == bcol_channel) { if (net->channel == 0) { snprintf(rline + rofft, max - rofft, "%3s", "---"); } else { snprintf(rline + rofft, max - rofft, "%3d", net->channel); } rofft += 3; } else if (b == bcol_freq_mhz) { unsigned int maxmhz = 0, maxval = 0; for (map::const_iterator fmi = net->freq_mhz_map.begin(); fmi != net->freq_mhz_map.end(); ++fmi) { if (fmi->second > maxval) maxmhz = fmi->first; } if (maxmhz == 0) { snprintf(rline + rofft, max - rofft, "%4s", "----"); } else { snprintf(rline + rofft, max - rofft, "%4d", maxmhz); } rofft += 4; } else if (b == bcol_packdata) { snprintf(rline + rofft, max - rofft, "%5d", net->data_packets); rofft += 5; } else if (b == bcol_packllc) { snprintf(rline + rofft, max - rofft, "%5d", net->llc_packets); rofft += 5; } else if (b == bcol_packcrypt) { snprintf(rline + rofft, max - rofft, "%5d", net->crypt_packets); rofft += 5; } else if (b == bcol_bssid) { snprintf(rline + rofft, max - rofft, "%-17s", net->bssid.Mac2String().c_str()); rofft += 17; } else if (b == bcol_packets) { snprintf(rline + rofft, max - rofft, "%5d", net->llc_packets + net->data_packets); rofft += 5; } else if (b == bcol_beaconperc) { if (net->lastssid == NULL || (net->lastssid != NULL && (net->lastssid->beaconrate == 0)) || time(0) - net->last_time > 5) { snprintf(rline + rofft, max - rofft, "%-4s", " ---"); } else { // Kluge the beacons down to the rate, revisit this later if we // want to add IDS sensitivity based on an over-abundance of // beacons or something if (net->lastssid->beacons > net->lastssid->beaconrate) net->lastssid->beacons = net->lastssid->beaconrate; snprintf(rline + rofft, max - rofft, "%3.0f%%", ((double) net->lastssid->beacons / (double) net->lastssid->beaconrate) * 100); } rofft += 4; } else if (b == bcol_clients) { // TODO - handle clients snprintf(rline + rofft, max - rofft, "%4d", (int) net->client_map.size()); rofft += 4; } else if (b == bcol_datasize) { char dt = ' '; long int ds = 0; if (net->datasize < 1024) { ds = net->datasize; dt = 'B'; } else if (net->datasize < (1024*1024)) { ds = net->datasize / 1024; dt = 'K'; } else { ds = net->datasize / 1024 / 1024; dt = 'M'; } snprintf(rline + rofft, max - rofft, "%4ld%c", ds, dt); rofft += 5; } else if (b == bcol_signalbar) { // TODO - signalbar snprintf(rline + rofft, max - rofft, "TODO "); rofft += 8; } else if (b == bcol_signal_dbm) { if (time(0) - net->last_time > 5) { snprintf(rline + rofft, max - rofft, "---"); } else { snprintf(rline + rofft, max - rofft, "%3d", net->snrdata.last_signal_dbm); } rofft += 3; } else if (b == bcol_signal_rssi) { if (time(0) - net->last_time > 5) { snprintf(rline + rofft, max - rofft, "---"); } else { snprintf(rline + rofft, max - rofft, "%3d", net->snrdata.last_signal_rssi); } rofft += 3; } else if (b == bcol_manuf) { snprintf(rline + rofft, max - rofft, "%-10.10s", net->manuf.c_str()); rofft += 10; } else if (b == bcol_ip) { snprintf(rline + rofft, max - rofft, "%-15.15s", inet_ntoa(net->guess_ipdata.ip_addr_block)); rofft += 15; } else if (b == bcol_iprange) { string r = string(inet_ntoa(net->guess_ipdata.ip_addr_block)) + "/" + string(inet_ntoa(net->guess_ipdata.ip_netmask)); snprintf(rline + rofft, max - rofft, "%-31.31s", r.c_str()); rofft += 31; } else if (b == bcol_11dcountry) { if (net->lastssid == NULL) { snprintf(rline + rofft, max - rofft, "---"); } else if (net->lastssid->dot11d_vec.size() == 0) { snprintf(rline + rofft, max - rofft, "---"); } else { snprintf(rline + rofft, max - rofft, "%-3.3s", net->lastssid->dot11d_country.c_str()); } rofft += 3; } else if (b == bcol_seenby) { string clist; if (net->source_map.size() == 0) clist = "----"; for (map::iterator sdi = net->source_map.begin(); sdi != net->source_map.end(); ++sdi) { if ((kci = cardmap->find(sdi->second->source_uuid)) == cardmap->end()) { clist += "(Unk) "; } else { clist += kci->second->name + string(" "); } } snprintf(rline + rofft, max - rofft, "%-10.10s", clist.c_str()); rofft += 10; } else { continue; } if (rofft < (max - 1)) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } // column loop return rofft; } void Kis_Netlist::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_inactive, "panel_textdis_color"); parent_panel->InitColorPref("netlist_normal_color", "green,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_normal], "netlist_normal_color"); parent_panel->InitColorPref("netlist_wep_color", "red,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_wep], "netlist_wep_color"); parent_panel->InitColorPref("netlist_crypt_color", "yellow,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_crypt], "netlist_crypt_color"); parent_panel->InitColorPref("netlist_group_color", "blue,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_group], "netlist_group_color"); parent_panel->InitColorPref("netlist_decrypt_color", "hi-magenta,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_decrypt], "netlist_decrypt_color"); parent_panel->InitColorPref("netlist_header_color", "blue,black"); parent_panel->ColorFromPref(color_map[kis_netlist_color_header], "netlist_header_color"); wattrset(window, color_inactive); // This is the largest we should ever expect a window to be wide, so // we'll consider it a reasonable static line size char rline[1024]; int rofft = 0; // Used to track number of lines needed for expanded info int nlines = 0; int recovered_lines = 0; int redraw = 0; time_t now = time(0); // Printed line and a temp string to hold memory, used for cache // aliasing char *pline; string pt; if ((sort_mode != netsort_autofit && sort_mode != netsort_recent) && (selected_line < first_line || selected_line > (int) draw_vec->size())) selected_line = first_line; // Get any updated columns UpdateBColPrefs(); UpdateBExtPrefs(); // Column headers if (colhdr_cache == "") { // Space for the group indicator rofft = 1; rline[0] = ' '; for (unsigned c = 0; c < display_bcols.size(); c++) { bssid_columns b = display_bcols[c]; if (b == bcol_decay) { snprintf(rline + rofft, 1024 - rofft, " "); rofft += 1; } else if (b == bcol_name) { snprintf(rline + rofft, 1024 - rofft, "%-20.20s", "Name"); rofft += 20; } else if (b == bcol_shortname) { snprintf(rline + rofft, 1024 - rofft, "%-10.10s", "Name"); rofft += 10; } else if (b == bcol_nettype) { snprintf(rline + rofft, 1024 - rofft, "T"); rofft += 1; } else if (b == bcol_crypt) { snprintf(rline + rofft, 1024 - rofft, "C"); rofft += 1; } else if (b == bcol_channel) { snprintf(rline + rofft, 1024 - rofft, " Ch"); rofft += 3; } else if (b == bcol_freq_mhz) { snprintf(rline + rofft, 1024 - rofft, "Freq"); rofft += 4; } else if (b == bcol_packdata) { snprintf(rline + rofft, 1024 - rofft, " Data"); rofft += 5; } else if (b == bcol_packllc) { snprintf(rline + rofft, 1024 - rofft, " LLC"); rofft += 5; } else if (b == bcol_packcrypt) { snprintf(rline + rofft, 1024 - rofft, "Crypt"); rofft += 5; } else if (b == bcol_bssid) { snprintf(rline + rofft, 1024 - rofft, "%-17s", "BSSID"); rofft += 17; } else if (b == bcol_packets) { snprintf(rline + rofft, 1024 - rofft, " Pkts"); rofft += 5; } else if (b == bcol_clients) { snprintf(rline + rofft, 1024 - rofft, "Clnt"); rofft += 4; } else if (b == bcol_datasize) { snprintf(rline + rofft, 1024 - rofft, " Size"); rofft += 5; } else if (b == bcol_signalbar) { snprintf(rline + rofft, 1024 - rofft, "Signal "); rofft += 8; } else if (b == bcol_beaconperc) { snprintf(rline + rofft, 1024 - rofft, "Bcn%%"); rofft += 4; } else if (b == bcol_signal_dbm) { snprintf(rline + rofft, 1024 - rofft, "Sig"); rofft += 3; } else if (b == bcol_signal_rssi) { snprintf(rline + rofft, 1024 - rofft, "Sig"); rofft += 3; } else if (b == bcol_manuf) { snprintf(rline + rofft, 1024 - rofft, "%-10.10s", "Manuf"); rofft += 10; } else if (b == bcol_11dcountry) { snprintf(rline + rofft, 1024 - rofft, "%-3.3s", "Cty"); rofft += 3; } else if (b == bcol_seenby) { snprintf(rline + rofft, 1024 - rofft, "%-10.10s", "Seen By"); rofft += 10; } else if (b == bcol_ip) { snprintf(rline + rofft, 1024 - rofft, "%-15.15s", "Best-Guess IP"); rofft += 15; } else if (b == bcol_iprange) { snprintf(rline + rofft, 1024 - rofft, "%-31.31s", "Best-Guess IP Range"); rofft += 31; } if (rofft < 1023) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } colhdr_cache = rline; } // Draw the cached header // Make a padded header int padlen = ex - sx - colhdr_cache.length(); if (padlen < 0) padlen = 0; string pcache = colhdr_cache + string(padlen, ' '); if (active) wattrset(window, color_map[kis_netlist_color_header]); Kis_Panel_Specialtext::Mvwaddnstr(window, sy, sx, "\004u" + pcache + "\004U", lx - 1, parent_panel); if (draw_vec->size() == 0) { if (active) wattrset(window, color_map[kis_netlist_color_normal]); if (kpinterface->FetchNetClient() == NULL) { mvwaddnstr(window, sy + 2, sx, "[ --- Not connected to a Kismet server --- ]", lx); } else { mvwaddnstr(window, sy + 2, sx, "[ --- No networks seen --- ]", ex - sx); } return; } if (sort_mode == netsort_autofit) first_line = 0; // For as many lines as we can fit int dpos = 1; for (unsigned int x = first_line; x < draw_vec->size() && dpos <= viewable_lines; x++) { Kis_Display_NetGroup *ng = (*draw_vec)[x]; Netracker::tracked_network *meta = ng->FetchNetwork(); int color = -1; nlines = 0; // Recompute the output line if the display for that network is dirty // or if the network has changed recently enough. No sense caching whats // going to keep thrashing every update if (meta != NULL && (ng->DispDirty() || ((now - meta->last_time) < 10))) { // Space for the group indicator rofft = 1; if (ng->FetchNumNetworks() > 1) { if (ng->GetExpanded()) { rline[0] = '-'; } else { rline[0] = '+'; } color = kis_netlist_color_group; } else { rline[0] = ' '; } rofft = PrintNetworkLine(ng, NULL, rofft, rline, 1024); // Fill to the end if we need to for highlighting if (rofft < (ex - sx) && ((ex - sx) - rofft) < 1024) { memset(rline + rofft, ' ', (ex - sx) - rofft); rline[(ex - sx)] = '\0'; } if (color < 0 && meta->lastssid != NULL) { if (meta->lastssid->cryptset == crypt_wep || (meta->lastssid->cryptset & crypt_wpa_migmode)) { color = kis_netlist_color_wep; } else if (meta->lastssid->cryptset != 0) { color = kis_netlist_color_crypt; } } // Override color with decrypted color if (meta->decrypted) { color = kis_netlist_color_decrypt; } ng->SetColor(color); ng->SetLineCache(rline); pline = rline; } else { // Pull the cached line pt = ng->GetLineCache(); pline = (char *) pt.c_str(); color = ng->GetColor(); } nlines++; if (color <= 0) color = kis_netlist_color_normal; if (active) wattrset(window, color_map[color]); // Draw the line if (selected_line == (int) x && sort_mode != netsort_autofit && active) wattron(window, WA_REVERSE); // Kis_Panel_Specialtext::Mvwaddnstr(window, sy + dpos, sx, pline, ex); // We don't use our specialtext here since we don't want something that // snuck into the SSID to affect the printing mvwaddnstr(window, sy + dpos, sx, pline, ex - sx); dpos++; // Draw the expanded info for the network if (selected_line == (int) x && sort_mode != netsort_autofit && active && show_ext_info && ng->GetExpanded() == 0) { // Cached print lines (also a direct shortcut into the cache // storage system) vector *pevcache; // Reset the offset we're printing into on rline rofft = 0; pevcache = ng->GetDetCache(); map *cardmap = kpinterface->FetchNetCardMap(); map::iterator kci; // If we're dirty, we don't have details cached, or it's been // w/in 10 seconds, we recalc the details if (ng->DispDirty() || (meta != NULL && (now - meta->last_time) < 10) || pevcache->size() == 0) { // Directly manipulate the cache ptr, probably bad pevcache->clear(); rofft = 1; rline[0] = ' '; // Offset for decay if we have it if (display_bcols[0] == bcol_decay) { snprintf(rline + rofft, 1024 - rofft, " "); rofft += 2; } for (unsigned int c = 0; c < display_bexts.size(); c++) { bssid_extras e = display_bexts[c]; if (e == bext_lastseen) { snprintf(rline + rofft, 1024 - rofft, "Last seen: %.15s", ctime((const time_t *) &(meta->last_time)) + 4); rofft += 26; } else if (e == bext_crypt) { snprintf(rline + rofft, 1024 - rofft, "Crypt:"); rofft += 6; if (meta->lastssid == NULL) { snprintf(rline + rofft, 1024 - rofft, " Unknown"); rofft += 8; } else { if ((meta->lastssid->cryptset == 0)) { snprintf(rline + rofft, 1024 - rofft, " None"); rofft += 5; } if ((meta->lastssid->cryptset == crypt_wep)) { snprintf(rline + rofft, 1024 - rofft, " WEP"); rofft += 4; } if ((meta->lastssid->cryptset & crypt_layer3)) { snprintf(rline + rofft, 1024 - rofft, " L3"); rofft += 3; } if ((meta->lastssid->cryptset & crypt_wpa_migmode)) { snprintf(rline + rofft, 1024 - rofft, " WPA Migration Mode"); rofft += 19; } if ((meta->lastssid->cryptset & crypt_wep40)) { snprintf(rline + rofft, 1024 - rofft, " WEP40"); rofft += 6; } if ((meta->lastssid->cryptset & crypt_wep104)) { snprintf(rline + rofft, 1024 - rofft, " WEP104"); rofft += 7; } if ((meta->lastssid->cryptset & crypt_tkip)) { snprintf(rline + rofft, 1024 - rofft, " TKIP"); rofft += 5; } if ((meta->lastssid->cryptset & crypt_wpa)) { snprintf(rline + rofft, 1024 - rofft, " WPA"); rofft += 4; } if ((meta->lastssid->cryptset & crypt_psk)) { snprintf(rline + rofft, 1024 - rofft, " PSK"); rofft += 4; } if ((meta->lastssid->cryptset & crypt_aes_ocb)) { snprintf(rline + rofft, 1024 - rofft, " AESOCB"); rofft += 7; } if ((meta->lastssid->cryptset & crypt_aes_ccm)) { snprintf(rline + rofft, 1024 - rofft, " AESCCM"); rofft += 7; } if ((meta->lastssid->cryptset & crypt_leap)) { snprintf(rline + rofft, 1024 - rofft, " LEAP"); rofft += 5; } if ((meta->lastssid->cryptset & crypt_ttls)) { snprintf(rline + rofft, 1024 - rofft, " TTLS"); rofft += 5; } if ((meta->lastssid->cryptset & crypt_tls)) { snprintf(rline + rofft, 1024 - rofft, " TLS"); rofft += 4; } if ((meta->lastssid->cryptset & crypt_peap)) { snprintf(rline + rofft, 1024 - rofft, " PEAP"); rofft += 5; } if ((meta->lastssid->cryptset & crypt_isakmp)) { snprintf(rline + rofft, 1024 - rofft, " ISAKMP"); rofft += 7; } if ((meta->lastssid->cryptset & crypt_pptp)) { snprintf(rline + rofft, 1024 - rofft, " PPTP"); rofft += 5; } if (meta->lastssid->cryptset & crypt_fortress) { snprintf(rline + rofft, 1024 - rofft, " Fortress"); rofft += 5; } if (meta->lastssid->cryptset & crypt_keyguard) { snprintf(rline + rofft, 1024 - rofft, " Keyguard"); rofft += 5; } } } else if (e == bext_bssid) { snprintf(rline + rofft, 1024 - rofft, "BSSID: %s", meta->bssid.Mac2String().c_str()); rofft += 24; } else if (e == bext_manuf) { snprintf(rline + rofft, 1024 - rofft, "Manuf: %s", meta->manuf.c_str()); rofft += kismin(17, 7 + meta->manuf.length()); } else if (e == bext_seenby) { string clist; if (meta->source_map.size() == 0) clist = "----"; for (map::iterator sdi = meta->source_map.begin(); sdi != meta->source_map.end(); ++sdi) { if ((kci = cardmap->find(sdi->second->source_uuid)) == cardmap->end()) { clist += "(Unk) "; } else { clist += kci->second->name + string(" "); } } snprintf(rline + rofft, 1024 - rofft, "SeenBy: %-10.10s", clist.c_str()); rofft += kismin(18, 8 + clist.length()); } else { continue; } if (rofft < 1023) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } // Fill to the end if we need to for highlighting if (rofft < (ex - sx) && ((ex - sx) - rofft) < 1024) { memset(rline + rofft, ' ', (ex - sx) - rofft); rline[(ex - sx)] = '\0'; } pevcache->push_back(rline); } /* Handle scrolling down if we're at the end. Yeah, this is * obnoxious. */ for (unsigned int d = 0; d < pevcache->size(); d++) { nlines++; // If we need to get more space... if (dpos >= viewable_lines && (int) x != first_line) { // We're going to have to redraw this whole thing anyhow redraw = 1; // If we've recovered enough lines, we just take some away. // Don't try to take away from the first one - if it doesn't // fit, TFB. if (recovered_lines > 0) { recovered_lines--; } else { // Otherwise we need to start sliding down the list to // recover some lines. selected is the raw # in dv, // not the visual offset, so we don't have to play any // games there. recovered_lines += (*draw_vec)[first_line]->GetNLines(); first_line++; } } // Only draw if we don't need to redraw everything, but always // increment the dpos so we know how many lines we need to recover if (redraw == 0 && dpos < viewable_lines) mvwaddnstr(window, sy + dpos, sx, (*pevcache)[d].c_str(), ex - sx); dpos++; } } else if (sort_mode != netsort_autofit && ng->GetExpanded()) { vector *gevcache; rofft = 0; gevcache = ng->GetGrpCache(); if (ng->DispDirty() || (meta != NULL && (now - meta->last_time) < 10) || gevcache->size() == 0) { vector *nv = ng->FetchNetworkVec(); // Directly manipulate the cache ptr, probably bad gevcache->clear(); for (unsigned int n = 0; n < nv->size(); n++) { rofft = 2; rline[0] = ' '; rline[1] = ' '; rofft = PrintNetworkLine(ng, (*nv)[n], rofft, rline, 1024); // Fill to the end if we need to for highlighting if (rofft < (ex - sx) && ((ex - sx) - rofft) < 1024) { memset(rline + rofft, ' ', (ex - sx) - rofft); rline[(ex - sx)] = '\0'; } gevcache->push_back(rline); } } for (unsigned int d = 0; d < gevcache->size(); d++) { nlines++; if (dpos >= viewable_lines && (int) x != first_line) { redraw = 1; if (recovered_lines > 0) { recovered_lines--; } else { recovered_lines += (*draw_vec)[first_line]->GetNLines(); first_line++; } } if (redraw == 0 && dpos < viewable_lines) mvwaddnstr(window, sy + dpos, sx, (*gevcache)[d].c_str(), ex - sx); dpos++; } } if (selected_line == (int) x && sort_mode != netsort_autofit && active) wattroff(window, WA_REVERSE); ng->SetNLines(nlines); last_line = x; // Set it no longer dirty (we've cached everything along the way // so this is safe to do here regardless) ng->SetDispDirty(0); } // Netlist // Call ourselves again and redraw if we have to. Only loop on 1, -1 used // for first-line overflow if (redraw == 1) { DrawComponent(); } } void Kis_Netlist::Activate(int subcomponent) { active = 1; } void Kis_Netlist::Deactivate() { active = 0; } int Kis_Netlist::KeyPress(int in_key) { if (visible == 0) return 0; ostringstream osstr; // Selected is the literal selected line in the display vector, not the // line # on the screen, so when we scroll, we need to scroll it as well // Autofit gets no love if (sort_mode == netsort_autofit) return 0; if (in_key == KEY_DOWN || in_key == '+') { if (selected_line < first_line || selected_line > last_line) { selected_line = first_line; return 0; } // If we're at the bottom and we can go further, slide the selection // and the first line down if (selected_line == last_line && last_line < (int) draw_vec->size() - 1) { selected_line++; first_line++; } else if (selected_line != last_line) { // Otherwise we just move the selected line selected_line++; } } else if (in_key == KEY_UP || in_key == '-') { if (selected_line < first_line || selected_line > last_line) { selected_line = first_line; return 0; } // If we're at the top and we can go further, slide the selection // and the first line UP if (selected_line == first_line && first_line > 0) { selected_line--; first_line--; } else if (selected_line != first_line) { // Just slide up the selection selected_line--; } } else if (in_key == KEY_PPAGE) { if (selected_line < 0 || selected_line > last_line) { selected_line = first_line; return 0; } first_line = kismax(0, first_line - viewable_lines); selected_line = first_line; } else if (in_key == KEY_NPAGE) { if (selected_line < 0 || selected_line > last_line) { selected_line = first_line; return 0; } first_line = kismin((int) draw_vec->size() - 1, first_line + viewable_lines); selected_line = first_line; } else if (in_key == ' ') { if (selected_line < 0 || selected_line > last_line || selected_line >= (int) draw_vec->size()) { return 0; } Kis_Display_NetGroup *ng = (*draw_vec)[selected_line]; if (ng->FetchNumNetworks() <= 1) return 0; ng->SetExpanded(!ng->GetExpanded()); } else if (in_key == '\n' || in_key == KEY_ENTER) { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); } return 0; } int Kis_Netlist::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; // Not in our bounds at all if ((mevent->bstate != 4 && mevent->bstate != 8) || mwy < sy || mwy > ey || mwx < sx || mwx > ex) return 0; // Not in a selectable mode, we consume it but do nothing if (sort_mode == netsort_autofit) return 1; // Modify coordinates to be inside the widget mwy -= sy; int vpos = first_line + mwy - 1; if (selected_line < vpos) vpos--; if (vpos < 0 || vpos > (int) draw_vec->size()) return 1; // Double-click, trigger the activation callback if ((last_mouse_click - globalreg->timestamp.tv_sec < 1 && selected_line == vpos) || mevent->bstate == 8) { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } last_mouse_click = globalreg->timestamp.tv_sec; // Otherwise select it and center the network list on it selected_line = vpos; first_line = selected_line - (ly / 2); if (first_line < 0) first_line = 0; return 1; } Kis_Display_NetGroup *Kis_Netlist::FetchSelectedNetgroup() { if (sort_mode == netsort_autofit) return NULL; if (selected_line < 0 || selected_line >= (int) draw_vec->size()) return NULL; return (*draw_vec)[selected_line]; } const char *info_bits_details[][2] = { { "elapsed", "Elapsed time" }, { "numnets", "Number of networks" }, { "numpkts", "Number of packets" }, { "pktrate", "Packet rate" }, { "numfilter", "Number of filtered packets" }, { "sources", "Packet sources" }, { NULL, NULL} }; // Callbacks void KisInfobits_Configured(CLICONF_CB_PARMS) { ((Kis_Info_Bits *) auxptr)->NetClientConfigure(kcli, recon); } void KisInfobits_AddCli(KPI_ADDCLI_CB_PARMS) { ((Kis_Info_Bits *) auxptr)->NetClientAdd(netcli, add); } void KisInfobits_INFO(CLIPROTO_CB_PARMS) { ((Kis_Info_Bits *) auxptr)->Proto_INFO(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisInfobits_TIME(CLIPROTO_CB_PARMS) { ((Kis_Info_Bits *) auxptr)->Proto_TIME(globalreg, proto_string, proto_parsed, srccli, auxptr); } Kis_Info_Bits::Kis_Info_Bits(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Packbox(in_globalreg, in_panel) { kpinterface = in_panel->FetchPanelInterface(); num_networks = num_packets = packet_rate = filtered_packets = 0; addref = kpinterface->Add_NetCli_AddCli_CB(KisInfobits_AddCli, (void *) this); // Set up our inherited vbox attributes SetPackV(); SetHomogenous(0); SetSpacing(1); info_color_normal = -1; parent_panel->InitColorPref("info_normal_color", "white,black"); title = new Kis_Free_Text(globalreg, parent_panel); title->SetColorPrefs("info_normal_color", "info_normal_color"); title->SetText("\004uKismet\004U"); title->SetAlignment(1); title->Show(); Pack_End(title, 0, 0); asm_time_num = TokenNullJoin(&asm_time_fields, time_fields); asm_info_num = TokenNullJoin(&asm_info_fields, info_fields); UpdatePrefs(); } Kis_Info_Bits::~Kis_Info_Bits() { kpinterface->Remove_Netcli_AddCli_CB(addref); kpinterface->Remove_All_Netcli_Conf_CB(KisInfobits_Configured); kpinterface->Remove_All_Netcli_ProtoHandler("TIME", KisInfobits_TIME, this); kpinterface->Remove_All_Netcli_ProtoHandler("INFO", KisInfobits_INFO, this); } int Kis_Info_Bits::UpdatePrefs() { string ibits; if ((ibits = kpinterface->prefs->FetchOpt("NETINFO_ITEMS")) == "") { ibits = "elapsed,numnets,numpkts,pktrate,numfilter"; kpinterface->prefs->SetOpt("NETINFO_ITEMS", ibits, 1); } if (kpinterface->prefs->FetchOptDirty("NETINFO_ITEMS") == 0) { return 0; } kpinterface->prefs->SetOptDirty("NETINFO_ITEMS", 0); infovec.clear(); // Unpack the vbox and remove the widgets for (map::iterator x = infowidgets.begin(); x != infowidgets.end(); ++x) { Pack_Remove(x->second); delete(x->second); } infowidgets.clear(); vector toks = StrTokenize(ibits, ","); string t; int optnum; Kis_Free_Text *ft; for (unsigned int x = 0; x < toks.size(); x++) { t = StrLower(toks[x]); if (t == "elapsed") { optnum = info_elapsed; infovec.push_back(info_elapsed); } else if (t == "numnets") { optnum = info_numnets; } else if (t == "numpkts") { optnum = info_numpkts; } else if (t == "pktrate") { optnum = info_pktrate; } else if (t == "numfilter") { optnum = info_filtered; } else { _MSG("Unknown info panel item '" + t + "', skipping.", MSGFLAG_INFO); continue; } infovec.push_back(optnum); ft = new Kis_Free_Text(globalreg, parent_panel); ft->SetColorPrefs("info_normal_color", "info_normal_color"); ft->Show(); ft->SetAlignment(1); Pack_End(ft, 0, 0); infowidgets[optnum] = ft; } return 1; } void Kis_Info_Bits::DrawComponent() { UpdatePrefs(); if (kpinterface->FetchNetClient() == NULL || (kpinterface->FetchNetClient() != NULL && kpinterface->FetchNetClient()->Valid() <= 0)) { vector titletext = title->GetText(); if (titletext.size() == 1) { titletext.push_back("\004rNot\004R"); titletext.push_back("\004rConnected\004R"); title->SetText(titletext); } } Kis_Panel_Packbox::DrawComponent(); } void Kis_Info_Bits::NetClientConfigure(KisNetClient *in_cli, int in_recon) { first_time = in_cli->FetchServerStarttime(); title->SetText("\004u" + in_cli->FetchServerName() + "\004U"); if (in_cli->RegisterProtoHandler("TIME", asm_time_fields, KisInfobits_TIME, this) < 0) { _MSG("Could not register TIME protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("INFO", asm_info_fields, KisInfobits_INFO, this) < 0) { _MSG("Could not register INFO protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } } void Kis_Info_Bits::NetClientAdd(KisNetClient *in_cli, int add) { if (add == 0) return; in_cli->AddConfCallback(KisInfobits_Configured, 1, this); } void Kis_Info_Bits::Proto_TIME(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_time_num) { return; } unsigned int ttime; if (sscanf((*proto_parsed)[0].word.c_str(), "%u", &ttime) != 1) { return; } last_time = ttime; if (infowidgets.find(info_elapsed) != infowidgets.end()) { vector it; char t[20]; time_t el = last_time - first_time; it.push_back("\004bElapsed\004B"); snprintf(t, 20, "%02d:%02d.%02d", (int) (el / 60) / 60, (int) (el / 60) % 60, (int) (el % 60)); it.push_back(t); infowidgets[info_elapsed]->SetText(it); } } void Kis_Info_Bits::Proto_INFO(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < (unsigned int) asm_info_num) { return; } int tint; int fnum = 0; vector it(2); char n[20]; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { return; } num_networks = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { return; } num_packets = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { return; } packet_rate = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { return; } filtered_packets = tint; if (infowidgets.find(info_numnets) != infowidgets.end()) { it[0] = "\004bNetworks\004B"; snprintf(n, 20, "%d", num_networks); it[1] = n; infowidgets[info_numnets]->SetText(it); } if (infowidgets.find(info_numpkts) != infowidgets.end()) { it[0] = "\004bPackets\004B"; snprintf(n, 20, "%d", num_packets); it[1] = n; infowidgets[info_numpkts]->SetText(it); } if (infowidgets.find(info_pktrate) != infowidgets.end()) { it[0] = "\004bPkt/Sec\004B"; snprintf(n, 20, "%d", packet_rate); it[1] = n; infowidgets[info_pktrate]->SetText(it); } if (infowidgets.find(info_filtered) != infowidgets.end()) { it[0] = "\004bFiltered\004B"; snprintf(n, 20, "%d", filtered_packets); it[1] = n; infowidgets[info_filtered]->SetText(it); } } const common_col_pref client_column_details[] = { { "decay", "Recent activity", ccol_decay }, { "MAC", "MAC address", ccol_mac }, { "BSSID", "BSSID client is attached to", ccol_bssid }, { "Type", "Type of client", ccol_type }, /* { "SSID", "SSID client is attached to", ccol_ssid }, */ { "crypt", "Client uses encryption", ccol_packcrypt }, { "packdata", "Number of data packets", ccol_packdata }, { "packllc", "Number of control packets", ccol_packllc }, { "packcrypt", "Number of encrypted packets", ccol_packcrypt }, { "packets", "Total number of packets", ccol_packets }, { "datasize", "Total data captured", ccol_datasize }, { "signal_dbm", "Last signal level in dBm", ccol_signal_dbm }, { "signal_rssi", "Last signal level in RSSI", ccol_signal_rssi }, { "freq_mhz", "Last-seen frequency", ccol_freq_mhz }, { "manuf", "Manufacturer", ccol_manuf }, { "dhcphost", "DHCP host name", ccol_dhcphost }, { "dhcpos", "DHCP OS vendor", ccol_dhcpvendor }, { "ip", "Best-guess IP address", ccol_ip }, { NULL, NULL, 0 } }; const common_col_pref client_extras_details[] = { { "lastseen", "Last seen timestamp", cext_lastseen }, { "crypt", "Encryption types", cext_crypt }, { "ip", "IP Address", cext_ip }, { "manuf", "Manufacturer info", cext_manuf }, { "dhcphost", "DHCP host name", cext_dhcphost }, { "dhcpos", "DHCP OS vendor", cext_dhcpvendor }, { NULL, NULL, 0} }; int Event_Clientlist_Update(TIMEEVENT_PARMS) { ((Kis_Clientlist *) parm)->UpdateTrigger(); return 1; } Kis_Clientlist::Kis_Clientlist(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { kpinterface = in_panel->FetchPanelInterface(); followdng = 0; ccol_pref_t = cext_pref_t = sort_pref_t = 0; viewable_lines = 0; viewable_cols = 0; sort_mode = clientsort_autofit; // Don't need to add client protocol dissectors here since we're not // actually talking to the server, we're leeching off the netlist // code which handled everything for us already updateref = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &Event_Clientlist_Update, (void *) this); hpos = 0; selected_line = -1; first_line = 0; last_line = 0; for (int x = 0; x < 5; x++) color_map[x] = 0; color_inactive = 0; dng = NULL; last_mouse_click = 0; // Set default preferences for BSSID columns if we don't have any in the // preferences file, then update the column vector UpdateCColPrefs(); UpdateCExtPrefs(); UpdateSortPrefs(); UpdateTrigger(); } Kis_Clientlist::~Kis_Clientlist() { // Remove the timer globalreg->timetracker->RemoveTimer(updateref); } int Kis_Clientlist::UpdateCColPrefs() { string pcols; // Use a default set of columns if we don't find one if ((pcols = kpinterface->prefs->FetchOpt("CLIENTLIST_COLUMNS")) == "") { pcols = "decay,mac,type,freq_mhz,packets,datasize,manuf"; kpinterface->prefs->SetOpt("CLIENTLIST_COLUMNS", pcols, time(0)); } if (kpinterface->prefs->FetchOptDirty("CLIENTLIST_COLUMNS") == ccol_pref_t && display_ccols.size() != 0) return 0; ccol_pref_t = kpinterface->prefs->FetchOptDirty("CLIENTLIST_COLUMNS"); display_ccols.clear(); vector toks = StrTokenize(pcols, ","); string t; // Clear the cached headers colhdr_cache = ""; for (unsigned int x = 0; x < toks.size(); x++) { t = StrLower(toks[x]); int set = 0; for (unsigned int y = 0; client_column_details[y].pref != NULL; y++) { if (t == StrLower(client_column_details[y].pref)) { display_ccols.push_back((client_columns) client_column_details[y].ref); set = 1; break; } } if (set == 0) _MSG("Unknown client display column '" + t + "', skipping.", MSGFLAG_INFO); } return 1; } int Kis_Clientlist::UpdateCExtPrefs() { string pcols; // Use a default set of columns if we don't find one if ((pcols = kpinterface->prefs->FetchOpt("CLIENTLIST_EXTRAS")) == "") { pcols = "lastseen,crypt,ip"; kpinterface->prefs->SetOpt("CLIENTLIST_EXTRAS", pcols, time(0)); } if (kpinterface->prefs->FetchOptDirty("CLIENTLIST_EXTRAS") == cext_pref_t && display_cexts.size() != 0) return 0; cext_pref_t = kpinterface->prefs->FetchOptDirty("CLIENTLIST_EXTRAS"); display_cexts.clear(); vector toks = StrTokenize(pcols, ","); string t; for (unsigned int x = 0; x < toks.size(); x++) { t = StrLower(toks[x]); int set = 0; for (unsigned int y = 0; client_extras_details[y].pref != NULL; y++) { if (t == StrLower(client_extras_details[y].pref)) { display_cexts.push_back((client_extras) client_extras_details[y].ref); set = 1; break; } } if (set == 0) _MSG("Unknown display column '" + t + "', skipping.", MSGFLAG_INFO); } return 1; } int Kis_Clientlist::UpdateSortPrefs() { string sort; // Use a default set of columns if we don't find one if ((sort = kpinterface->prefs->FetchOpt("CLIENTLIST_SORT")) == "") { sort = "auto"; kpinterface->prefs->SetOpt("CLIENTLIST_SORT", sort, time(0)); } if (kpinterface->prefs->FetchOptDirty("CLIENTLIST_SORT") == sort_pref_t) return 0; sort_pref_t = kpinterface->prefs->FetchOptDirty("CLIENTLIST_SORT"); sort = StrLower(sort); if (sort == "auto") sort_mode = clientsort_autofit; else if (sort == "recent") sort_mode = clientsort_recent; else if (sort == "first") sort_mode = clientsort_first; else if (sort == "first_desc") sort_mode = clientsort_first_desc; else if (sort == "last") sort_mode = clientsort_last; else if (sort == "last_desc") sort_mode = clientsort_last_desc; else if (sort == "mac") sort_mode = clientsort_mac; else if (sort == "type") sort_mode = clientsort_type; else if (sort == "packets") sort_mode = clientsort_packets; else if (sort == "packets_desc") sort_mode = clientsort_packets_desc; else sort_mode = clientsort_autofit; return 1; } void Kis_Clientlist::SetPosition(int isx, int isy, int iex, int iey) { Kis_Panel_Component::SetPosition(isx, isy, iex, iey); viewable_lines = ly - 1; viewable_cols = ex; } void Kis_Clientlist::UpdateDNG(void) { if (kpinterface->FetchMainPanel() == NULL) return; if (kpinterface->FetchMainPanel()->FetchSelectedNetgroup() != dng) { dng = NULL; UpdateTrigger(); } } void Kis_Clientlist::UpdateTrigger(void) { if (kpinterface->FetchMainPanel() == NULL) return; if (kpinterface->FetchMainPanel()->FetchSelectedNetgroup() != dng && (dng == NULL || followdng)) { dng = kpinterface->FetchMainPanel()->FetchSelectedNetgroup(); display_vec.clear(); hpos = 0; selected_line = -1; first_line = 0; last_line = 0; } if (dng == NULL) { hpos = 0; selected_line = -1; first_line = 0; last_line = 0; return; } // Add all the networks clients together vector *dngnv = dng->FetchNetworkVec(); for (unsigned int n = 0; n < dngnv->size(); n++) { for (map::iterator x = (*dngnv)[n]->client_map.begin(); x != (*dngnv)[n]->client_map.end(); ++x) { int match = 0; for (unsigned int y = 0; y < display_vec.size(); y++) { // This sucks but uses less ram if (display_vec[y].cli == x->second) { match = 1; break; } } if (match == 0) { display_client dc; dc.cli = x->second; dc.num_lines = 0; dc.color = -1; // Force them dirty dc.cli->dirty = 1; display_vec.push_back(dc); } } } // Show extended info? if (kpinterface->prefs->FetchOpt("CLIENTLIST_SHOWEXT") == "0") show_ext_info = 0; else show_ext_info = 1; switch (sort_mode) { case clientsort_autofit: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_LastDesc()); break; case clientsort_first: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_First()); break; case clientsort_first_desc: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_FirstDesc()); break; case clientsort_last: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_Last()); break; case clientsort_last_desc: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_LastDesc()); break; case clientsort_mac: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_Mac()); break; case clientsort_type: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_Type()); break; case clientsort_packets: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_Packets()); break; case clientsort_packets_desc: stable_sort(display_vec.begin(), display_vec.end(), KisClientlist_Sort_PacketsDesc()); break; default: break; } } int Kis_Clientlist::PrintClientLine(Netracker::tracked_client *cli, int rofft, char *rline, int max) { if (cli == NULL) return rofft; for (unsigned c = 0; c < display_ccols.size(); c++) { client_columns b = display_ccols[c]; if (b == ccol_decay) { char d; int to; to = time(0) - cli->last_time; if (to < 3) d = '!'; else if (to < 5) d = '.'; else d = ' '; snprintf(rline + rofft, max - rofft, "%c", d); rofft += 1; } else if (b == ccol_ssid) { snprintf(rline + rofft, max - rofft, "%-20.20s", "n/a"); rofft += 20; } else if (b == ccol_freq_mhz) { unsigned int maxmhz = 0, maxval = 0; for (map::const_iterator fmi = cli->freq_mhz_map.begin(); fmi != cli->freq_mhz_map.end(); ++fmi) { if (fmi->second > maxval) maxmhz = fmi->first; } if (maxmhz == 0) { snprintf(rline + rofft, max - rofft, "%4s", "----"); } else { snprintf(rline + rofft, max - rofft, "%4d", maxmhz); } rofft += 4; } else if (b == ccol_manuf) { snprintf(rline + rofft, max - rofft, "%-20.20s", cli->manuf.c_str()); rofft += 20; } else if (b == ccol_packdata) { snprintf(rline + rofft, max - rofft, "%5d", cli->data_packets); rofft += 5; } else if (b == ccol_packllc) { snprintf(rline + rofft, max - rofft, "%5d", cli->llc_packets); rofft += 5; } else if (b == ccol_packcrypt) { snprintf(rline + rofft, max - rofft, "%5d", cli->crypt_packets); rofft += 5; } else if (b == ccol_mac) { snprintf(rline + rofft, max - rofft, "%-17s", cli->mac.Mac2String().c_str()); rofft += 17; } else if (b == ccol_type) { string t; if (cli->type == client_fromds) t = "Wired/AP"; else if (cli->type == client_tods || cli->type == client_established) t = "Wireless"; else if (cli->type == client_adhoc) t = "Adhoc"; else t = "Unknown"; snprintf(rline + rofft, max - rofft, "%-8s", t.c_str()); rofft += 8; } else if (b == ccol_packets) { snprintf(rline + rofft, max - rofft, "%5d", cli->llc_packets + cli->data_packets); rofft += 5; } else if (b == ccol_datasize) { char dt = ' '; long int ds = 0; if (cli->datasize < 1024) { ds = cli->datasize; dt = 'B'; } else if (cli->datasize < (1024*1024)) { ds = cli->datasize / 1024; dt = 'K'; } else { ds = cli->datasize / 1024 / 1024; dt = 'M'; } snprintf(rline + rofft, max - rofft, "%4ld%c", ds, dt); rofft += 5; } else if (b == ccol_signal_dbm) { if (time(0) - cli->last_time > 5) { snprintf(rline + rofft, max - rofft, "---"); } else { snprintf(rline + rofft, max - rofft, "%3d", cli->snrdata.last_signal_dbm); } rofft += 3; } else if (b == ccol_signal_rssi) { if (time(0) - cli->last_time > 5) { snprintf(rline + rofft, max - rofft, "---"); } else { snprintf(rline + rofft, max - rofft, "%3d", cli->snrdata.last_signal_rssi); } rofft += 3; } else if (b == ccol_dhcphost) { if (cli->dhcp_host.length() == 0) { snprintf(rline + rofft, max - rofft, "%-10.10s", "---"); } else { snprintf(rline + rofft, max - rofft, "%-10.10s", cli->dhcp_host.c_str()); } rofft += 10; } else if (b == ccol_dhcpvendor) { if (cli->dhcp_vendor.length() == 0) { snprintf(rline + rofft, max - rofft, "%-10.10s", "---"); } else { snprintf(rline + rofft, max - rofft, "%-10.10s", cli->dhcp_vendor.c_str()); } rofft += 10; } else if (b == ccol_ip) { snprintf(rline + rofft, max - rofft, "%-15.15s", inet_ntoa(cli->guess_ipdata.ip_addr_block)); rofft += 15; } else { continue; } if (rofft < (max - 1)) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } // column loop return rofft; } void Kis_Clientlist::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_inactive, "panel_textdis_color"); parent_panel->InitColorPref("clientlist_normal_color", "white,black"); parent_panel->ColorFromPref(color_map[kis_clientlist_color_normal], "clientlist_normal_color"); parent_panel->InitColorPref("clientlist_ap_color", "blue,black"); parent_panel->ColorFromPref(color_map[kis_clientlist_color_ap], "clientlist_ap_color"); parent_panel->InitColorPref("clientlist_wireless_color", "green,black"); parent_panel->ColorFromPref(color_map[kis_clientlist_color_wireless], "clientlist_wireless_color"); parent_panel->InitColorPref("clientlist_adhoc_color", "magenta,black"); parent_panel->ColorFromPref(color_map[kis_clientlist_color_adhoc], "clientlist_adhoc_color"); parent_panel->InitColorPref("clientlist_header_color", "blue,black"); parent_panel->ColorFromPref(color_map[kis_clientlist_color_header], "clientlist_header_color"); wattrset(window, color_inactive); // This is the largest we should ever expect a window to be wide, so // we'll consider it a reasonable static line size char rline[1024]; int rofft = 0; // Used to track number of lines needed for expanded info int nlines = 0; int recovered_lines = 0; int redraw = 0; time_t now = time(0); // Printed line and a temp string to hold memory, used for cache // aliasing char *pline; string pt; if ((sort_mode != clientsort_autofit && sort_mode != clientsort_recent) && (selected_line < first_line || selected_line > (int) display_vec.size())) selected_line = first_line; // Get any updated columns UpdateCColPrefs(); UpdateCExtPrefs(); // Column headers if (colhdr_cache.length() == 0) { rofft = 0; for (unsigned c = 0; c < display_ccols.size(); c++) { client_columns cc = display_ccols[c]; if (cc == ccol_decay) { snprintf(rline + rofft, 1024 - rofft, " "); rofft += 1; } else if (cc == ccol_ssid) { snprintf(rline + rofft, 1024 - rofft, "%-20.20s", "SSID"); rofft += 20; } else if (cc == ccol_mac) { snprintf(rline + rofft, 1024 - rofft, "%-17s", "MAC"); rofft += 17; } else if (cc == ccol_type) { snprintf(rline + rofft, 1024 - rofft, "%-8s", "Type"); rofft += 8; } else if (cc == ccol_bssid) { snprintf(rline + rofft, 1024 - rofft, "%-17s", "BSSID"); rofft += 17; } else if (cc == ccol_manuf) { snprintf(rline + rofft, 1024 - rofft, "%-20.20s", "Manuf"); rofft += 20; } else if (cc == ccol_dhcphost) { snprintf(rline + rofft, 1024 - rofft, "%-10.10s", "DHCP Host"); rofft += 10; } else if (cc == ccol_dhcpvendor) { snprintf(rline + rofft, 1024 - rofft, "%-10.10s", "DHCP OS"); rofft += 10; } else if (cc == ccol_ip) { snprintf(rline + rofft, 1024 - rofft, "%-15.15s", "Best-Guess IP"); rofft += 15; } else if (cc == ccol_freq_mhz) { snprintf(rline + rofft, 1024 - rofft, "Freq"); rofft += 4; } else if (cc == ccol_packdata) { snprintf(rline + rofft, 1024 - rofft, " Data"); rofft += 5; } else if (cc == ccol_packllc) { snprintf(rline + rofft, 1024 - rofft, " LLC"); rofft += 5; } else if (cc == ccol_packcrypt) { snprintf(rline + rofft, 1024 - rofft, "Crypt"); rofft += 5; } else if (cc == ccol_packets) { snprintf(rline + rofft, 1024 - rofft, " Pkts"); rofft += 5; } else if (cc == ccol_datasize) { snprintf(rline + rofft, 1024 - rofft, " Size"); rofft += 5; } else if (cc == ccol_signal_dbm) { snprintf(rline + rofft, 1024 - rofft, "Sig"); rofft += 3; } else if (cc == ccol_signal_rssi) { snprintf(rline + rofft, 1024 - rofft, "Sig"); rofft += 3; } if (rofft < 1023) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } colhdr_cache = rline; } // Make a padded header int padlen = ex - sx - colhdr_cache.length(); if (padlen < 0) padlen = 0; string pcache = colhdr_cache + string(padlen, ' '); if (active) wattrset(window, color_map[kis_clientlist_color_header]); Kis_Panel_Specialtext::Mvwaddnstr(window, sy, sx, "\004u" + pcache + "\004U", lx - 1, parent_panel); if (display_vec.size() == 0) { if (active) wattrset(window, color_map[kis_clientlist_color_normal]); if (kpinterface->FetchNetClient() == 0) { mvwaddnstr(window, sy + 2, sx, "[ --- Not connected to a Kismet server --- ]", lx); } else { mvwaddnstr(window, sy + 2, sx, "[ --- No clients seen --- ]", lx); } return; } if (sort_mode == clientsort_autofit) first_line = 0; // For as many lines as we can fit int dpos = 1; for (unsigned int x = first_line; x < display_vec.size() && dpos <= viewable_lines; x++) { Netracker::tracked_client *tc = display_vec[x].cli; int color = -1; nlines = 0; // Recompute the output line if the client is dirty or changed // recently if (tc != NULL && (tc->dirty || ((now - tc->last_time) < 10))) { rofft = 0; rofft = PrintClientLine(tc, rofft, rline, 1024); // Fill to the end if we need to for highlighting if (rofft < (ex - sx) && ((ex - sx) - rofft) < 1024) { memset(rline + rofft, ' ', (ex - sx) - rofft); rline[(ex - sx)] = '\0'; } pline = rline; if (display_vec[x].cli->type == client_fromds) color = kis_clientlist_color_ap; else if (display_vec[x].cli->type == client_tods || display_vec[x].cli->type == client_established) color = kis_clientlist_color_wireless; else if (display_vec[x].cli->type == client_adhoc) color = kis_clientlist_color_adhoc; else color = kis_clientlist_color_normal; display_vec[x].cached_line = pline; display_vec[x].color = color; } else { pline = (char *) display_vec[x].cached_line.c_str(); color = display_vec[x].color; } nlines++; if (color < 0) color = kis_clientlist_color_normal; if (active) wattrset(window, color_map[color]); // Draw the line if (selected_line == (int) x && sort_mode != clientsort_autofit && active) wattron(window, WA_REVERSE); // Kis_Panel_Specialtext::Mvwaddnstr(window, sy + dpos, sx, pline, ex); // We don't use our specialtext here since we don't want something that // snuck into the SSID to affect the printing mvwaddnstr(window, sy + dpos, sx, pline, lx); dpos++; // Draw the expanded info for the client if (selected_line == (int) x && sort_mode != clientsort_autofit && active && show_ext_info) { // Cached print lines (also a direct shortcut into the cache // storage system) vector *pevcache; // Reset the offset we're printing into on rline rofft = 0; pevcache = &(display_vec[x].cached_details); // If we're dirty, we don't have details cached, or it's been // w/in 10 seconds, we recalc the details if (display_vec[x].cli->dirty || (now - display_vec[x].cli->last_time < 10) || pevcache->size() == 0) { rofft = 1; rline[0] = ' '; pevcache->clear(); // Offset for decay if we have it first if (display_ccols[0] == ccol_decay) { snprintf(rline + rofft, 1024 - rofft, " "); rofft += 2; } for (unsigned int c = 0; c < display_cexts.size(); c++) { client_extras e = display_cexts[c]; if (e == cext_lastseen) { snprintf(rline + rofft, 1024 - rofft, "Last seen: %.15s", ctime((const time_t *) &(display_vec[x].cli->last_time)) + 4); rofft += 26; #if 0 } else if (e == cext_crypt) { snprintf(rline + rofft, 1024 - rofft, "Crypt:"); rofft += 6; if (cc == NULL) { snprintf(rline + rofft, 1024 - rofft, " Unknown"); rofft += 8; } else { if ((display_vec[x].cli->cryptset == 0)) { snprintf(rline + rofft, 1024 - rofft, " None"); rofft += 5; } if ((display_vec[x].cli->cryptset == crypt_wep)) { snprintf(rline + rofft, 1024 - rofft, " WEP"); rofft += 4; } if ((display_vec[x].cli->cryptset & crypt_layer3)) { snprintf(rline + rofft, 1024 - rofft, " L3"); rofft += 3; } if ((display_vec[x].cli->cryptset & crypt_wpa_migmode)) { snprintf(rline + rofft, 1024 - rofft, " WPA Migration Mode"); rofft += 19; } if ((display_vec[x].cli->cryptset & crypt_wep40)) { snprintf(rline + rofft, 1024 - rofft, " WEP40"); rofft += 6; } if ((display_vec[x].cli->cryptset & crypt_wep104)) { snprintf(rline + rofft, 1024 - rofft, " WEP104"); rofft += 7; } if ((display_vec[x].cli->cryptset & crypt_tkip)) { snprintf(rline + rofft, 1024 - rofft, " TKIP"); rofft += 5; } if ((display_vec[x].cli->cryptset & crypt_wpa)) { snprintf(rline + rofft, 1024 - rofft, " WPA"); rofft += 4; } if ((display_vec[x].cli->cryptset & crypt_psk)) { snprintf(rline + rofft, 1024 - rofft, " PSK"); rofft += 4; } if ((display_vec[x].cli->cryptset & crypt_aes_ocb)) { snprintf(rline + rofft, 1024 - rofft, " AESOCB"); rofft += 7; } if ((display_vec[x].cli->cryptset & crypt_aes_ccm)) { snprintf(rline + rofft, 1024 - rofft, " AESCCM"); rofft += 7; } if ((display_vec[x].cli->cryptset & crypt_leap)) { snprintf(rline + rofft, 1024 - rofft, " LEAP"); rofft += 5; } if ((display_vec[x].cli->cryptset & crypt_ttls)) { snprintf(rline + rofft, 1024 - rofft, " TTLS"); rofft += 5; } if ((display_vec[x].cli->cryptset & crypt_tls)) { snprintf(rline + rofft, 1024 - rofft, " TLS"); rofft += 4; } if ((display_vec[x].cli->cryptset & crypt_peap)) { snprintf(rline + rofft, 1024 - rofft, " PEAP"); rofft += 5; } if ((display_vec[x].cli->cryptset & crypt_isakmp)) { snprintf(rline + rofft, 1024 - rofft, " ISAKMP"); rofft += 7; } if ((display_vec[x].cli->cryptset & crypt_pptp)) { snprintf(rline + rofft, 1024 - rofft, " PPTP"); rofft += 5; } if ((display_vec[x].cli->cryptset & crypt_fortress)) { snprintf(rline + rofft, 1024 - rofft, " Fortress"); rofft += 9; } if ((display-vec[x].cli->cryptset & crypt_keyguard)) { snprintf(rline + rofft, 1024 - rofft, " Keyguard"); rofft += 9; } } #endif } else if (e == cext_ip) { string i = string(inet_ntoa(display_vec[x].cli->guess_ipdata.ip_addr_block)); snprintf(rline + rofft, 1024 - rofft, "IP: %s", i.c_str()); rofft += 4 + i.length(); } else if (e == cext_manuf) { snprintf(rline + rofft, 1024 - rofft, "Manuf: %s", display_vec[x].cli->manuf.c_str()); rofft += kismin(17, 7 + display_vec[x].cli->manuf.length()); } else if (e == cext_dhcphost) { if (display_vec[x].cli->dhcp_host.length() > 0) { snprintf(rline + rofft, 1024 - rofft, "Host: %s", display_vec[x].cli->dhcp_host.c_str()); rofft += kismin(17, 6 + display_vec[x].cli->dhcp_host.length()); } } else if (e == cext_dhcpvendor) { if (display_vec[x].cli->dhcp_vendor.length() > 0) { snprintf(rline + rofft, 1024 - rofft, "DHCP OS: %s", display_vec[x].cli->dhcp_vendor.c_str()); rofft += kismin(17, 9 + display_vec[x].cli->dhcp_vendor.length()); } } else { continue; } if (rofft < 1023) { // Update the endline conditions rline[rofft++] = ' '; rline[rofft] = '\0'; } else { break; } } // Fill to the end if we need to for highlighting if (rofft < (ex - sx) && ((ex - sx) - rofft) < 1024) { memset(rline + rofft, ' ', (ex - sx) - rofft); rline[(ex - sx)] = '\0'; } pevcache->push_back(rline); } /* Handle scrolling down if we're at the end. Yeah, this is * obnoxious. */ for (unsigned int d = 0; d < pevcache->size(); d++) { nlines++; // If we need to get more space... if (dpos >= viewable_lines && (int) x != first_line) { // We're going to have to redraw this whole thing anyhow redraw = 1; // If we've recovered enough lines, we just take some away. // Don't try to take away from the first one - if it doesn't // fit, TFB. if (recovered_lines > 0) { recovered_lines--; } else { // Otherwise we need to start sliding down the list to // recover some lines. selected is the raw # in dv, // not the visual offset, so we don't have to play any // games there. recovered_lines += display_vec[first_line].num_lines; first_line++; } } // Only draw if we don't need to redraw everything, but always // increment the dpos so we know how many lines we need to recover if (redraw == 0 && dpos < viewable_lines) mvwaddnstr(window, sy + dpos, sx, (*pevcache)[d].c_str(), ex - sx); dpos++; } } if (selected_line == (int) x && sort_mode != clientsort_autofit && active) wattroff(window, WA_REVERSE); display_vec[x].num_lines = nlines; last_line = x; // Set it no longer dirty (we've cached everything along the way // so this is safe to do here regardless) display_vec[x].cli->dirty = 0; } // Netlist // Call ourselves again and redraw if we have to. Only loop on 1, -1 used // for first-line overflow if (redraw == 1) { DrawComponent(); } } void Kis_Clientlist::Activate(int subcomponent) { active = 1; } void Kis_Clientlist::Deactivate() { active = 0; } int Kis_Clientlist::KeyPress(int in_key) { if (visible == 0) return 0; ostringstream osstr; // Selected is the literal selected line in the display vector, not the // line # on the screen, so when we scroll, we need to scroll it as well // Autofit gets no love if (sort_mode == clientsort_autofit) return 0; if (in_key == KEY_DOWN || in_key == '+') { if (selected_line < first_line || selected_line > last_line) { selected_line = first_line; return 0; } // If we're at the bottom and we can go further, slide the selection // and the first line down if (selected_line == last_line && last_line < (int) display_vec.size() - 1) { selected_line++; first_line++; } else if (selected_line != last_line) { // Otherwise we just move the selected line selected_line++; } } else if (in_key == KEY_UP || in_key == '-') { if (selected_line < first_line || selected_line > last_line) { selected_line = first_line; return 0; } // If we're at the top and we can go further, slide the selection // and the first line UP if (selected_line == first_line && first_line > 0) { selected_line--; first_line--; } else if (selected_line != first_line) { // Just slide up the selection selected_line--; } } else if (in_key == KEY_PPAGE) { if (selected_line < 0 || selected_line > last_line) { selected_line = first_line; return 0; } first_line = kismax(0, first_line - viewable_lines); selected_line = first_line; } else if (in_key == KEY_NPAGE) { if (selected_line < 0 || selected_line > last_line) { selected_line = first_line; return 0; } first_line = kismin((int) display_vec.size() - 1, first_line + viewable_lines); selected_line = first_line; } else if (in_key == '\n' || in_key == KEY_ENTER) { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); } return 0; } int Kis_Clientlist::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; // Not in our bounds at all if ((mevent->bstate != 4 && mevent->bstate != 8) || mwy < sy || mwy > ey || mwx < sx || mwx > ex) return 0; // Not in a selectable mode, we consume it but do nothing if (sort_mode == clientsort_autofit) return 1; // Modify coordinates to be inside the widget mwy -= sy; int vpos = first_line + mwy - 1; if (selected_line < vpos) vpos--; if (vpos < 0 || vpos > (int) display_vec.size()) return 1; // Double-click, trigger the activation callback if ((last_mouse_click - globalreg->timestamp.tv_sec < 1 && selected_line == vpos) || mevent->bstate == 8) { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } last_mouse_click = globalreg->timestamp.tv_sec; // Otherwise select it and center the network list on it selected_line = vpos; first_line = selected_line - (ly / 2); if (first_line < 0) first_line = 0; return 1; } Kis_Display_NetGroup *Kis_Clientlist::FetchSelectedNetgroup() { return dng; } Netracker::tracked_client *Kis_Clientlist::FetchSelectedClient() { if (selected_line < 0 || selected_line >= (int) display_vec.size()) return NULL; return display_vec[selected_line].cli; } #endif // panel kismet-2013-03-R1b/packetsource_wext.cc0000664000175000017500000012045012124602454017523 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include "psutils.h" #ifdef HAVE_LINUX_WIRELESS // Some kernels include ethtool headers in wireless.h and seem to break // terribly if these aren't defined typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long u64; #include #include #include #endif #include "util.h" #if (defined(HAVE_LIBPCAP) && defined(SYS_LINUX) && defined(HAVE_LINUX_WIRELESS)) #include "packetsourcetracker.h" #include "packetsource_wext.h" #include "madwifing_control.h" #include "nl80211_control.h" PacketSource_Wext::PacketSource_Wext(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { scan_wpa = 0; wpa_timer_id = -1; wpa_sock = -1; memset(&wpa_local, 0, sizeof(struct sockaddr_un)); memset(&wpa_dest, 0, sizeof(struct sockaddr_un)); use_mac80211 = 0; opp_vap = 0; force_vap = 0; nlcache = nlfamily = NULL; ignore_primary_state = false; stored_channel = stored_mode = stored_privmode = stored_flags = -1; // Type derived by our higher parent if (type == "nokia770" || type == "nokia800" || type == "nokia810" || type == "nokiaitt") { SetValidateCRC(1); SetFCSBytes(4); } // Catch warning states if (type == "wl") { warning = "Detected 'wl' binary-only broadcom driver for interface " + interface + "; This driver does not provide monitor-mode support (which is " "required by Kismet) Try the in-kernel open source drivers for " "the Broadcom cards. Kismet will continue to attempt to use " "this card incase the drivers have recently added support, but " "this will probably fail."; _MSG(warning, MSGFLAG_PRINTERROR); } if (type == "orinoco_cs") { warning = "Detected 'orinoco_cs' driver for interface " + interface + "; This driver will not report packets in rfmon under many firmware " "versions. Kismet will continue trying to use it, however if you don't " "see any packets check `dmesg' and consider changing firmware on your " "card."; _MSG(warning, MSGFLAG_PRINTERROR); } ParseOptions(in_opts); // Don't warn about wpa_supplicant if we're going to use it string processes; if (scan_wpa == 0) { if (FindProcess("wpa_action", interface)) processes += "wpa_action "; if (FindProcess("wpa_supplicant", interface)) processes += "wpa_supplicant "; if (FindProcess("wpa_cli", interface)) processes += "wpa_cli "; } vector look_procs = StrTokenize("dhclient,ifplugd,dhcpbd,dhcpcd,NetworkManager,knetworkmanager," "avahi-daemon,wlanassistant,wifibox", ","); for (unsigned int x = 0; x < look_procs.size(); x++) if (FindProcess(look_procs[x], interface)) processes += look_procs[x] + string(" "); processes = processes.substr(0, processes.length() - 1); if (processes != "" && warning == "") { warning = "Detected the following processes that appear to be using the " "interface " + interface + ", which can cause problems with Kismet " "by changing the configuration of the network device: " + processes + ". If Kismet stops running or stops capturing packets, try killing " "one (or all) of these processes or stopping the network for this " "interface."; _MSG(warning, MSGFLAG_PRINTERROR); } } PacketSource_Wext::~PacketSource_Wext() { if (wpa_sock >= 0) close(wpa_sock); if (wpa_timer_id >= 0) globalreg->timetracker->RemoveTimer(wpa_timer_id); if (wpa_local_path != "") unlink(wpa_local_path.c_str()); } int PacketSource_Wext::OpenSource() { int r = PacketSource_Pcap::OpenSource(); if (r < 0) return r; if (DatalinkType() < 0) { if (pd != NULL) pcap_close(pd); return -1; } return 1; } int PacketSource_Wext::ParseOptions(vector *in_opts) { PacketSource_Pcap::ParseOptions(in_opts); // Force us to keep the primary interface still running if (FetchOptBoolean("ignoreprimary", in_opts, false)) { ignore_primary_state = true; _MSG("Source '" + interface + "' will ignore the primary interface " "up. This may cause conflicts with wpasupplicant / networkmanager", MSGFLAG_INFO); } if (FetchOpt("vap", in_opts) != "") { vap = FetchOpt("vap", in_opts); _MSG("Source '" + interface + "' will attempt to create a monitor-only " "VAP '" + vap + "' instead of reconfiguring the main interface", MSGFLAG_INFO); // Opportunistic VAP off when specified opp_vap = 0; } // Record if the VAP is absolutely forced (no passive blank option) // if (StrLower(FetchOpt("forcevap", in_opts)) == "true") if (FetchOptBoolean("forcevap", in_opts, 0)) force_vap = 1; // Turn on VAP by default // if (vap == "" && (FetchOpt("forcevap", in_opts) == "" || // StrLower(FetchOpt("forcevap", in_opts)) == "true")) { if (vap == "" && FetchOptBoolean("forcevap", in_opts, 1)) { if (vap == "") { // Only set a vap when we're not targetting a vap if (mac80211_find_parent(string(interface + "mon").c_str()) == "") { _MSG("Source '" + interface + "' will attempt to create and use a " "monitor-only VAP instead of reconfiguring the main interface", MSGFLAG_INFO); vap = interface + "mon"; } // Opportunistic VAP on opp_vap = 1; } } else if (vap == "") { _MSG("Source '" + interface + "' forced into non-vap mode, this will " "modify the provided interface.", MSGFLAG_INFO); } // if (FetchOpt("fcsfail", in_opts) == "true") { if (FetchOptBoolean("fcsfail", in_opts, 0)) { if (vap == "") { _MSG("Source '" + interface + "': 'fcsfail' enabled to tell " "mac80211 to report invalid packets, but not using a VAP. " "A vap must be specified with 'vap=' BEFORE the 'fcsfail' " "option.", MSGFLAG_PRINTERROR); } else { _MSG("Source '" + interface + "::" + vap + "': Telling mac80211 to report " "invalid packets which fail the FCS check. Forcing FCS " "validation on as well.", MSGFLAG_INFO); mac80211_flag_vec.push_back(nl80211_mntr_flag_fcsfail); validate_fcs = 1; } } // if (FetchOpt("plcpfail", in_opts) == "true") { if (FetchOptBoolean("plcpfail", in_opts, 0)) { if (vap == "") { _MSG("Source '" + interface + "': 'plcpfail' enabled to tell " "mac80211 to report invalid packets, but not using a VAP. " "A vap must be specified with 'vap=' BEFORE the 'plcpfail' " "option.", MSGFLAG_PRINTERROR); } else { _MSG("Source '" + interface + "::" + vap + "': Telling mac80211 to report " "invalid packets which fail the PLCP check. Forcing FCS " "validation on as well.", MSGFLAG_INFO); mac80211_flag_vec.push_back(nl80211_mntr_flag_plcpfail); validate_fcs = 1; } } wpa_path = FetchOpt("wpa_ctrl_path", in_opts); if (FetchOpt("wpa_scan", in_opts) != "") { if (wpa_path == "") _MSG("Source '" + interface + "' - requested wpa_scan assist from " "wpa_supplicant but no wpa_ctrl_path option, we'll use " "the defaults, set this path if your wpa_supplicant uses " "something else for the control socket", MSGFLAG_ERROR); // if (FetchOpt("hop", in_opts) == "" || FetchOpt("hop", in_opts) == "true") { if (FetchOptBoolean("hop", in_opts, 1)) { _MSG("Source '" + interface + "' - wpa_scan assist from wpa_supplicant " "requested but hopping not disabled, wpa_scan is meaningless on " "a hopping interface, so it will not be enabled.", MSGFLAG_ERROR); scan_wpa = 0; } else if (sscanf(FetchOpt("wpa_scan", in_opts).c_str(), "%d", &scan_wpa) != 1) { _MSG("Source '" + interface + "' - invalid wpa_scan interval, expected " "number (of seconds) between each scan", MSGFLAG_ERROR); scan_wpa = 0; } else { _MSG("Source '" + interface + "' - using wpa_supplicant to assist with " "non-disruptive hopping", MSGFLAG_INFO); scan_wpa = 1; } if (wpa_path == "") wpa_path = "/var/run/wpa_supplicant"; } return 1; } int PacketSource_Wext::AutotypeProbe(string in_device) { string sysdriver; // Examine the /sys filesystem to try to figure out what kind of driver // we have here sysdriver = Linux_GetSysDrv(in_device.c_str()); // Most of the linux drivers now behave sanely if (sysdriver == "iwl4965" || sysdriver == "iwl3945" || sysdriver == "iwlagn" || sysdriver == "adm8211" || sysdriver == "ath5k" || sysdriver == "ath9k" || sysdriver == "b43" || sysdriver == "ath5k_pci" || sysdriver == "ath9k_pci" || sysdriver == "b43legacy" || sysdriver == "hostap" || sysdriver == "libertas" || sysdriver == "p54" || sysdriver == "libertas_usb" || sysdriver == "libertas_tf" || sysdriver == "prism54" || sysdriver == "rndis_wlan" || sysdriver == "rt2500pci" || sysdriver == "rt73usb" || sysdriver == "rt2860" || sysdriver == "rt2800usb" || sysdriver == "rt2x00pci" || sysdriver == "rt61pci" || sysdriver == "rt2400pci" || sysdriver == "rt2x00usb" || sysdriver == "rt2400pci" || sysdriver == "rt61pci" || sysdriver == "rtl8180" || sysdriver == "zd1201" || sysdriver == "rtl8187" || sysdriver == "zd1211rw" || // These don't seem to work but i'll autodet anyhow sysdriver == "rt2870sta" || // These drivers don't behave sanely but throw errors when we open them sysdriver == "wl" || sysdriver == "orinoco" || sysdriver == "orinoco_cs") { // Set the weaksource type to what we derived warning = ""; type = sysdriver; return 1; } // Detect unknown mac80211 devices, ask for help, assume wext if (Linux_GetSysDrvAttr(in_device.c_str(), "phy80211")) { type = "mac80211"; warning = "Didn't understand driver '" + sysdriver + "' for interface '" + in_device + "', but it looks like a mac80211 device so Kismet " "will use the generic options for it. Please post on the Kismet " "forum or stop by the IRC channel and report what driver it was."; _MSG(warning, MSGFLAG_PRINTERROR); return 1; } return 0; } int PacketSource_Wext::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("adm8211", this, "IEEE80211b", 1); tracker->RegisterPacketProto("acx100", this, "IEEE80211b", 1); tracker->RegisterPacketProto("admtek", this, "IEEE80211b", 1); tracker->RegisterPacketProto("atmel_usb", this, "IEEE80211b", 1); tracker->RegisterPacketProto("ath5k", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("ath5k_pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("ath9k", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("ath9k_pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("bcm43xx", this, "IEEE80211b", 1); tracker->RegisterPacketProto("b43", this, "IEEE80211b", 1); tracker->RegisterPacketProto("b43legacy", this, "IEEE80211b", 1); tracker->RegisterPacketProto("hostap", this, "IEEE80211b", 1); tracker->RegisterPacketProto("ipw2100", this, "IEEE80211b", 1); tracker->RegisterPacketProto("ipw2200", this, "IEEE80211b", 1); tracker->RegisterPacketProto("ipw2915", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("ipw3945", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("iwl3945", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("iwl4965", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("iwlagn", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("libertas", this, "IEEE80211b", 1); tracker->RegisterPacketProto("libertas_usb", this, "IEEE80211b", 1); tracker->RegisterPacketProto("libertas_tf", this, "IEEE80211b", 1); tracker->RegisterPacketProto("nokia770", this, "IEEE80211b", 1); tracker->RegisterPacketProto("nokia800", this, "IEEE80211b", 1); tracker->RegisterPacketProto("nokia810", this, "IEEE80211b", 1); tracker->RegisterPacketProto("nokiaitt", this, "IEEE80211b", 1); tracker->RegisterPacketProto("orinoco", this, "IEEE80211b", 1); tracker->RegisterPacketProto("orinoco_cs", this, "IEEE80211b", 1); tracker->RegisterPacketProto("prism54", this, "IEEE80211b", 1); tracker->RegisterPacketProto("p54", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rndis_wlan", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2400", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2500", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2400pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2500pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2x00pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2800usb", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt61pci", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt73", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt73usb", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2860", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2860sta", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt2870sta", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt8180", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rt8187", this, "IEEE80211g", 1); tracker->RegisterPacketProto("rtl8180", this, "IEEE80211b", 1); tracker->RegisterPacketProto("rtl8187", this, "IEEE80211g", 1); tracker->RegisterPacketProto("wl", this, "IEEE80211b", 1); tracker->RegisterPacketProto("zd1211", this, "IEEE80211b", 1); tracker->RegisterPacketProto("zd1201", this, "IEEE80211b", 1); tracker->RegisterPacketProto("zd1211rw", this, "IEEE80211b", 1); tracker->RegisterPacketProto("wext", this, "IEEE80211b", 1); tracker->RegisterPacketProto("wl12xx", this, "IEEE80211b", 1); tracker->RegisterPacketProto("mac80211", this, "IEEE80211b", 1); return 1; } int wext_ping_wpasup_event(TIMEEVENT_PARMS) { return ((PacketSource_Wext *) parm)->ScanWpaSupplicant(); } void PacketSource_Wext::OpenWpaSupplicant() { wpa_local_path = "/tmp/kis_wpa_ctrl_" + parent + "_" + IntToString(getpid()); // Register the timer now so it can try to reconnect us if (scan_wpa && wpa_timer_id < 0) wpa_timer_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * scan_wpa, NULL, 1, wext_ping_wpasup_event, this); if (scan_wpa && wpa_sock < 0) { wpa_sock = socket(PF_UNIX, SOCK_DGRAM, 0); wpa_local.sun_family = AF_UNIX; snprintf(wpa_local.sun_path, sizeof(wpa_local.sun_path), "%s", wpa_local_path.c_str()); if (bind(wpa_sock, (struct sockaddr *) &wpa_local, sizeof(wpa_local)) < 0) { _MSG("Source '" + parent + "' failed to bind local socket for " "wpa_supplicant, disabling scan_wpa: " + string(strerror(errno)), MSGFLAG_PRINTERROR); close(wpa_sock); return; } else { wpa_dest.sun_family = AF_UNIX; snprintf(wpa_dest.sun_path, sizeof(wpa_dest.sun_path), "%s", (wpa_path + "/" + parent).c_str()); if (connect(wpa_sock, (struct sockaddr *) &wpa_dest, sizeof(wpa_dest)) < 0) { _MSG("Source '" + parent + "' failed to connect to wpa_supplicant " "control socket " + wpa_path + "/" + parent + ". Make sure " "that the wpa_ctrl_path option is set correctly.", MSGFLAG_PRINTERROR); close(wpa_sock); return; } } // Set it nonblocking, and we'll just check that our whole command // got written each time, not going to bother making a real queue fcntl(wpa_sock, F_SETFL, fcntl(wpa_sock, F_GETFL, 0) | O_NONBLOCK); unlink(wpa_local_path.c_str()); } } int PacketSource_Wext::ScanWpaSupplicant() { // If we're in error state, don't do anything (and shut down anything we had) if (FetchError() && wpa_sock >= 0) { close(wpa_sock); wpa_sock = -1; return 0; } // Otherwise if our sock is broken, open it (and next time we come back // we'll do something with it) if (wpa_sock < 0) { OpenWpaSupplicant(); return 1; } const char *scan = "SCAN"; if (write(wpa_sock, scan, sizeof(scan)) != sizeof(scan)) { _MSG("Source '" + parent + "' error writing to wpa_supplicant socket, " "reopening connection: " + string(strerror(errno)), MSGFLAG_ERROR); close(wpa_sock); wpa_sock = -1; // We failed, try to open it as we go away OpenWpaSupplicant(); } return 1; } int PacketSource_Wext::EnableMonitor() { char errstr[STATUS_MAX]; int ret; if (Linux_GetSysDrvAttr(interface.c_str(), "phy80211")) { #ifdef HAVE_LINUX_NETLINK use_mac80211 = 1; if (mac80211_connect(interface.c_str(), &(globalreg->nlhandle), &nlcache, &nlfamily, errstr) < 0) { _MSG("Source '" + interface + "' failed to connect nl80211: " + errstr, MSGFLAG_PRINTERROR); return -1; } // always enable crc on phy80211 since they seem to report bogus // crap fairly often SetValidateCRC(1); #else warning = "Source '" + interface + "' uses phy80211/mac80211 drivers, but " "Kismet was not compiled with LibNL. This will almost definitely not " "work right, but continuing for now. Expect bad behavior."; _MSG(warning, MSGFLAG_PRINTERROR); use_mac80211 = 0; #endif } else { use_mac80211 = 0; } if (type == "ipw2200" || type == "ipw2100") { warning = "Detected 'ipw2200' or 'ipw2100' for interface " + interface + "; This driver will not change channel using mac80211 commands in most " "cases. Kismet will use legacy channel control commands."; _MSG(warning, MSGFLAG_PRINTERROR); use_mac80211 = 0; } if (vap != "" && opp_vap == 1 && use_mac80211 == 0) { _MSG("Source '" + interface + "' doesn't have mac80211 support, disabling " "VAP creation of default monitor mode VAP", MSGFLAG_PRINTERROR); vap = ""; } else if (vap != "" && opp_vap == 0 && use_mac80211 == 0) { _MSG("Source '" + interface + "' doesn't have mac80211 support, unable to " "create a VAP for capturing, specify the main device instead.", MSGFLAG_PRINTERROR); return -1; } // If we don't already have a parent interface, it's whatever was specified // as our interface; we'll make the vap if we need to and use this for // reconnect if (parent == "") parent = interface; // Try to grab the wireless mode before we go making vaps - don't make // a vap for an interface that is already in monitor mode. ignore failures // and set a bogus stored mode so that we don't bypass the vap creation. If // for some reason an interface doesn't exist but a vap can still be created // from it, we don't want to fall down if (Iwconfig_Get_Mode(interface.c_str(), errstr, &stored_mode) < 0) { stored_mode = IW_MODE_AUTO; } OpenWpaSupplicant(); // Defer the vap creation to here so we're sure we're root if (vap != "" && use_mac80211 && stored_mode == IW_MODE_MONITOR && force_vap == 0) { _MSG("Not creating a VAP for " + interface + " even though one was " "requested, since the interface is already in monitor mode. " "Perhaps an existing monitor mode VAP was specified. To override " "this and create a new monitor mode vap no matter what, use the " "forcevap=true source option", MSGFLAG_PRINTERROR); } else if (vap != "" && use_mac80211) { // If we're ignoring the primary state do nothing, otherwise shut it down if (!ignore_primary_state) { int fl; _MSG("Bringing down primary interface '" + parent + "' to prevent " "wpa_supplicant and NetworkManager from trying to configure it", MSGFLAG_INFO); if ((ret = Ifconfig_Get_Flags(parent.c_str(), errstr, &fl)) == 0) { fl &= ~IFF_UP; ret = Ifconfig_Set_Flags(parent.c_str(), errstr, fl); } if (ret < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); if (ret == ENODEV) { warning = "Failed to find interface '" + parent + "', it may not be " "present at this time, it may not exist at all, or there may " "be a problem with the driver (such as missing firmware)"; } else { warning = "Failed to bring up interface '" + parent + "', this " "often means there is a problem with the driver (such as " "missing firmware), check the output of `dmesg'."; } _MSG(warning, MSGFLAG_PRINTERROR); return -1; } } if (mac80211_createvap(parent.c_str(), vap.c_str(), errstr) < 0) { _MSG("Source '" + parent + "' failed to create mac80211 VAP: " + string(errstr), MSGFLAG_PRINTERROR); if (opp_vap) goto end_vap; return -1; } // Switch our main processing interface to the vap interface = vap; // Set the flags if we have any, vap must be down to do so if (mac80211_flag_vec.size() > 0) { int oldflags; Ifconfig_Get_Flags(interface.c_str(), errstr, &oldflags); if (Ifconfig_Set_Flags(interface.c_str(), errstr, oldflags & ~(IFF_UP | IFF_RUNNING)) < 0) { _MSG("Failed to bring down interface '" + interface + "' to " "configure monitor flags: " + string(errstr), MSGFLAG_PRINTERROR); } if (mac80211_setvapflag(interface.c_str(), mac80211_flag_vec, errstr) < 0) { _MSG("Source '" + parent + "' failed to set flags on VAP '" + interface + "': " + string(errstr), MSGFLAG_PRINTERROR); } } } // Yes, gotos suck. Yes, go away end_vap: // Try to grab the wireless mode if (Iwconfig_Get_Mode(interface.c_str(), errstr, &stored_mode) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to get current wireless mode for interface '" + interface + "', check your configuration and consult the Kismet README file", MSGFLAG_PRINTERROR); return -1; } if (use_mac80211) { int oldflags; Ifconfig_Get_Flags(interface.c_str(), errstr, &oldflags); if (Ifconfig_Set_Flags(interface.c_str(), errstr, oldflags & ~(IFF_UP | IFF_RUNNING)) < 0) { _MSG("Failed to bring down interface '" + interface + "' to " "configure monitor: " + string(errstr), MSGFLAG_PRINTERROR); return -1; } // Force rfmon and vap flags, set mode with nl80211 mac80211_flag_vec.push_back(nl80211_mntr_flag_control); mac80211_flag_vec.push_back(nl80211_mntr_flag_otherbss); if (mac80211_setvapflag(interface.c_str(), mac80211_flag_vec, errstr) < 0) { _MSG("Source '" + parent + "' failed to set flags on VAP '" + interface + "': " + string(errstr), MSGFLAG_PRINTERROR); } if (Ifconfig_Delta_Flags(interface.c_str(), errstr, IFF_UP | IFF_RUNNING | IFF_PROMISC) < 0) { _MSG("Failed to bring up interface '" + interface + "' after " "configuring flags, something is weird (probably with your driver) " "or your driver is missing firmware, check the output of 'dmesg': " + string(errstr), MSGFLAG_PRINTERROR); return -1; } return 0; } // If it's already in monitor, make sure it's up and we're done if (stored_mode == LINUX_WLEXT_MONITOR) { _MSG("Interface '" + interface + "' is already marked as being in " "monitor mode, leaving it as it is.", MSGFLAG_INFO); if (Ifconfig_Delta_Flags(interface.c_str(), errstr, IFF_UP | IFF_RUNNING | IFF_PROMISC) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to bring up interface '" + interface + "', this " "often means there is a problem with the driver (such as " "missing firmware), check the output of `dmesg'.", MSGFLAG_PRINTERROR); return -1; } return 0; } // Don't try this if we have a working rfmon interface, someone else // probably wants the headers to stay as they are // Try to set the monitor header mode, nonfatal if it doesn't work if (Iwconfig_Set_IntPriv(interface.c_str(), "monitor_type", 2, 0, errstr) < 0) { _MSG("Capture source '" + interface + "' doesn't appear to use the " "monitor_type iwpriv control.", MSGFLAG_INFO); } // Try to set the monitor header another way, nonfatal if it doesn't work if (Iwconfig_Set_IntPriv(interface.c_str(), "set_prismhdr", 1, 0, errstr) < 0) { _MSG("Capture source '" + interface + "' doesn't appear to use the " "set_prismhdr iwpriv control", MSGFLAG_INFO); } if (Iwconfig_Set_Mode(interface.c_str(), errstr, LINUX_WLEXT_MONITOR) < 0) { /* Bring the interface down and try again */ _MSG("Failed to set monitor mode on interface '" + interface + "' " "in current state, bringing interface down and trying again", MSGFLAG_ERROR); int oldflags; Ifconfig_Get_Flags(interface.c_str(), errstr, &oldflags); if (Ifconfig_Set_Flags(interface.c_str(), errstr, oldflags & ~(IFF_UP | IFF_RUNNING)) < 0) { _MSG("Failed to bring down interface '" + interface + "' to " "configure monitor mode: " + string(errstr), MSGFLAG_PRINTERROR); return -1; } if (Iwconfig_Set_Mode(interface.c_str(), errstr, LINUX_WLEXT_MONITOR) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to set monitor mode on interface '" + interface + "', " "even after bringing interface into a down state. This " "usually means your drivers either do not report monitor " "mode, use a different mechanism than Kismet expected " "to configure monitor mode, or that the user which started " "Kismet does not have permission to change the driver mode. " "Make sure you have the required version and have applied " "any patches needed to your drivers, and that you have " "configured the proper source type for Kismet. See the " "troubleshooting section of the Kismet README for more " "information.", MSGFLAG_PRINTERROR); Ifconfig_Set_Flags(interface.c_str(), errstr, oldflags); return -1; } } // Make sure it's up if nothing else if (Ifconfig_Delta_Flags(interface.c_str(), errstr, IFF_UP | IFF_RUNNING | IFF_PROMISC) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to bring up interface '" + interface + "', this " "often means there is a problem with the driver (such as " "missing firmware), check the output of `dmesg'.", MSGFLAG_PRINTERROR); return -1; } return 0; } int PacketSource_Wext::DisableMonitor() { char errstr[STATUS_MAX]; if (wpa_local_path != "") unlink(wpa_local_path.c_str()); // We don't really care if any of these things fail. Keep trying. if (stored_channel > 0) SetChannel(stored_channel); // We do care if this fails; reset the wireless mode if we need to and we're // not a VAP (those get left, we don't care) if (stored_mode > 0 && stored_mode != LINUX_WLEXT_MONITOR && vap == "") { if (Iwconfig_Set_Mode(interface.c_str(), errstr, stored_mode) < 0) { int oldflags; Ifconfig_Get_Flags(interface.c_str(), errstr, &oldflags); if (Ifconfig_Set_Flags(interface.c_str(), errstr, oldflags & ~(IFF_UP | IFF_RUNNING)) < 0) { _MSG("Failed to restore previous wireless mode for interface '" + interface + "'. It may be left in an unknown or unusable state.", MSGFLAG_PRINTERROR); return -1; } if (Iwconfig_Set_Mode(interface.c_str(), errstr, stored_mode) < 0) { _MSG("Failed to restore previous wireless mode for interface '" + interface + "'. It may be left in an unknown or unusable state.", MSGFLAG_PRINTERROR); return -1; } } } return PACKSOURCE_UNMONITOR_RET_OKWITHWARN; } int PacketSource_Wext::SetChannel(unsigned int in_ch) { char errstr[STATUS_MAX]; int err = 0; // Set and exit if we're ok if (use_mac80211) { if ((err = mac80211_setchannel_cache(interface.c_str(), globalreg->nlhandle, nlfamily, in_ch, 0, errstr)) >= 0) { consec_error = 0; return 1; } } else { if ((err = Iwconfig_Set_Channel(interface.c_str(), in_ch, errstr)) >= 0) { consec_error = 0; return 1; } } _MSG("Packet source '" + name + "' failed to set channel " + IntToString(in_ch) + ": " + errstr, MSGFLAG_PRINTERROR); if (err == -22 && use_mac80211) { _MSG("Failed to change channel on source '" + name +"' and it looks " "like the device is mac80211 based but does not accept channel control " "over nl80211. Kismet will fall back to using the IW* channel " "methods.", MSGFLAG_PRINTERROR); use_mac80211 = 0; return SetChannel(in_ch); } if (err == -2) { _MSG("Failed to change channel on source '" + name +"' and it looks " "like the device has been removed (or the drivers have lost track of " "it somehow)", MSGFLAG_ERROR); error = 1; return -1; } int curmode; if (Iwconfig_Get_Mode(interface.c_str(), errstr, &curmode) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to change channel on source '" + name + "' and " "failed to fetch current interface state when determining the " "cause of the error. It is likely that the drivers are in a " "broken or unavailable state.", MSGFLAG_PRINTERROR); error = 1; return -1; } if (curmode != LINUX_WLEXT_MONITOR) { _MSG("Failed to change channel on source '" + name + "'. " "It appears to no longer be in monitor mode. This can happen if " "the drivers enter an unknown or broken state, but usually indicate " "that an external program has changed the device mode. Make sure no " "network management tools (such as networkmanager) are running " "before starting Kismet.", MSGFLAG_PRINTERROR); error = 1; return -1; } return 1; } vector PacketSource_Wext::FetchSupportedChannels(string in_interface) { vector ret; char errstr[STATUS_MAX]; /* If we couldn't figure out what we are with mac80211, or if we don't * have mac80211, go on to iwcontrol */ if (mac80211_get_chanlist(in_interface.c_str(), &ret, errstr) <= 0 || ret.size() == 0) { /* I guess we don't really care about the return code here either */ Iwconfig_Get_Chanlist(in_interface.c_str(), errstr, &ret); } return ret; } int PacketSource_Wext::FetchHardwareChannel() { char errstr[STATUS_MAX] = ""; int chan = 0; // Failure to fetch a channel isn't necessarily a fatal error // and if we blow up badly enough that we can't get channels, we'll // blow up definitively on something else soon enough if ((chan = Iwconfig_Get_Channel(interface.c_str(), errstr)) < 0) { globalreg->messagebus->InjectMessage("Source '" + name + "': " + errstr, MSGFLAG_PRINTERROR); return -1; } last_channel = chan; return chan; } void PacketSource_Wext::FetchRadioData(kis_packet *in_packet) { // Don't fetch non-packetheader data since it's not likely to be // useful info. return; } PacketSource_Madwifi::PacketSource_Madwifi(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Wext(in_globalreg, in_interface, in_opts) { if (type == "madwifi_a" || type == "madwifing_a") { madwifi_type = 1; } else if (type == "madwifi_b" || type == "madwifing_g") { madwifi_type = 2; } else if (type == "madwifi_g" || type == "madwifing_g") { madwifi_type = 3; } else if (type == "madwifi_ag" || type == "madwifing_ag" || type == "madwifi") { madwifi_type = 0; } else { _MSG("Packetsource::MadWifi - Unknown source type '" + type + "'. " "Will treat it as auto radio type", MSGFLAG_PRINTERROR); madwifi_type = 0; } SetFCSBytes(4); vapdestroy = 1; // if (FetchOpt("vapkill", in_opts) != "" && FetchOpt("vapkill", in_opts) != "true") { if (FetchOptBoolean("vapkill", in_opts, 1)) { vapdestroy = 0; _MSG("Madwifi-NG source " + name + " " + interface + ": Disabling destruction " "of non-monitor VAPS because vapkill was not set to true in source " "options. This may cause capture problems with some driver versions.", MSGFLAG_INFO); } } int PacketSource_Madwifi::OpenSource() { int r = PacketSource_Pcap::OpenSource(); if (r < 0) return r; if (DatalinkType() < 0) { if (pd != NULL) pcap_close(pd); return -1; } return 1; } int PacketSource_Madwifi::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("madwifi", this, "IEEE80211b", 1); tracker->RegisterPacketProto("madwifi_a", this, "IEEE80211a", 1); tracker->RegisterPacketProto("madwifi_b", this, "IEEE80211b", 1); tracker->RegisterPacketProto("madwifi_g", this, "IEEE80211b", 1); tracker->RegisterPacketProto("madwifi_ag", this, "IEEE80211ab", 1); tracker->RegisterPacketProto("madwifing_a", this, "IEEE80211a", 1); tracker->RegisterPacketProto("madwifing_b", this, "IEEE80211b", 1); tracker->RegisterPacketProto("madwifing_g", this, "IEEE80211b", 1); tracker->RegisterPacketProto("madwifing_ag", this, "IEEE80211ab", 1); return 1; } int PacketSource_Madwifi::EnableMonitor() { // Try to get the vap list, if that succeeds we know we have a madwifi_ng // implementation char newdev[IFNAMSIZ]; vector vaplist; string monvap = ""; char errstr[1024]; int nvaps; shutdowndestroy = 1; nvaps = madwifing_list_vaps(interface.c_str(), &vaplist); for (unsigned int x = 0; x < vaplist.size(); x++) { int iwmode; // Don't bother looking at devices that look like the parent if (vaplist[x].find("wifi") != string::npos) continue; if (Iwconfig_Get_Mode(vaplist[x].c_str(), errstr, &iwmode) < 0) { _MSG("Madwifi source " + name + ": Could not get mode of VAP " + interface + "::" + vaplist[x] + ". Madwifi has historically had problems with " "normal mode and monitor mode VAPs operating at the same time. " "You may need to manually remove them.", MSGFLAG_PRINTERROR); sleep(1); continue; } if (iwmode == LINUX_WLEXT_MASTER) { _MSG("Madwifi source " + name + ": Found master-mode VAP " + interface + "::" + vaplist[x] + ". While Madwifi has historically had problems with normal " "and master mode VAPs operating at the same time, it will not " "be removed on the assumption you really want this. High packet " "loss may occur however, so you may want to remove this VAP " "manually.", MSGFLAG_PRINTERROR); sleep(1); continue; } if (iwmode != LINUX_WLEXT_MONITOR && vapdestroy) { _MSG("Madwifi source " + name + ": Found non-monitor-mode VAP " + interface + "::" + vaplist[x] + ". Because madwifi-ng has problems with normal and monitor " "vaps operating on the same device, this will be removed. If " "you want Kismet to ignore non-monitor-mode VAPs and not " "remove them, edit your config file to set the \"novapkill\" " "option: 'sourceopts=" + name + ":novapkill'", MSGFLAG_PRINTERROR); if (madwifing_destroy_vap(vaplist[x].c_str(), errstr) < 0) { _MSG("Madwifi source " + name + ": Failed to destroy vap " + interface + "::" + vaplist[x] + ": " + string(errstr), MSGFLAG_PRINTERROR); return -1; continue; } sleep(1); continue; } else if (iwmode != LINUX_WLEXT_MONITOR && vapdestroy == 0) { _MSG("Madwifi source " + name + ": Found non-monitor-mode VAP " + interface + "::" + vaplist[x] + ". Because the sourceopt \"novapkill\" is set for this " "source, it will not be removed. THIS MAY CAUSE PROBLEMS. " "Do not enable novapkill unless you know you want it.", MSGFLAG_PRINTERROR); continue; } else if (iwmode == LINUX_WLEXT_MONITOR) { _MSG("Madwifi source " + name + ": Found monitor-mode VAP " + interface + "::" + vaplist[x] + ". We'll use that instead of making a new one.", MSGFLAG_INFO); sleep(1); monvap = vaplist[x]; interface = vaplist[x]; continue; } } // If we're in a madwifi-ng model, build a vap. Don't build one if // we already have one, and dont change the mode on an existing monitor // vap. if (monvap == "") { // Find the parent device if (parent == "") { int p = madwifing_find_parent(&vaplist); // Just use the interface if we can't find a parent? This will // probably fail soon after, but whatever if (p < 0) parent = interface; else parent = vaplist[p]; } if (madwifing_build_vap(parent.c_str(), errstr, "kis", newdev, IEEE80211_M_MONITOR, IEEE80211_CLONE_BSSID) >= 0) { _MSG("Madwifi source " + name + " created monitor-mode VAP " + parent + "::" + newdev + ".", MSGFLAG_INFO); FILE *controlf; string cpath = "/proc/sys/net/" + string(newdev) + "/dev_type"; if ((controlf = fopen(cpath.c_str(), "w")) == NULL) { _MSG("Madwifi source " + name + ": Failed to open /proc/sys/net " "madwifi control interface to set radiotap mode. This may " "indicate a deeper problem, but it is not in itself a fatal " "error.", MSGFLAG_PRINTERROR); } else { fprintf(controlf, "803\n"); fclose(controlf); } interface = newdev; driver_ng = 1; } else { _MSG("Madwifi source " + name + ": Failed to create monitor VAP: " + string(errstr), MSGFLAG_PRINTERROR); } } else if (monvap != "") { driver_ng = 1; shutdowndestroy = 0; interface = monvap; } if (driver_ng && nvaps < 0) { _MSG("Madwifi source " + name + ": Able to build rfmon VAP, but unable " "to get a list of existing VAPs. This means something strange is " "happening with your system, or that you're running on an old " "kernel (2.4.x) which does not provide Controller to VAP mapping. " "Performance will likely be VERY poor if you do not remove non-rfmon " "vaps manually (if any exist) using wlanconfig.", MSGFLAG_PRINTERROR); sleep(1); } if (PacketSource_Wext::EnableMonitor() < 0) { return -1; } if (driver_ng) return 1; _MSG("Madwifi source " + name + ": Could not get a VAP list from madwifi-ng, " "assuming this is a madwifi-old source. If you are running madwifi-ng " "you MUST pass the wifiX control interface, NOT an athX VAP.", MSGFLAG_INFO); sleep(1); if (Iwconfig_Get_IntPriv(interface.c_str(), "get_mode", &stored_privmode, errstr) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to get the current radio mode of interface '" + interface + "'", MSGFLAG_PRINTERROR); return -1; } if (Iwconfig_Set_IntPriv(interface.c_str(), "mode", madwifi_type, 0, errstr) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to set the radio mode of interface '" + interface + "'. This " "is needed to set the a/b/g radio mode", MSGFLAG_PRINTERROR); return -1; } return 1; } int PacketSource_Madwifi::DisableMonitor() { char errstr[1024]; if (driver_ng && shutdowndestroy) { if (madwifing_destroy_vap(interface.c_str(), errstr) < 0) { _MSG("Madwifi source " + name + ": Failed to destroy vap " + interface + " on shutdown: " + string(errstr), MSGFLAG_PRINTERROR); return -1; } return PACKSOURCE_UNMONITOR_RET_OKWITHWARN; } if (Iwconfig_Set_IntPriv(interface.c_str(), "mode", stored_privmode, 0, errstr) < 0) { _MSG(errstr, MSGFLAG_PRINTERROR); _MSG("Failed to restore the stored radio mode for interface '" + interface + "'. The device may be left in an unknown or unusable " "state.", MSGFLAG_PRINTERROR); return -1; } if (PacketSource_Wext::DisableMonitor() < 0) { return -1; } return PACKSOURCE_UNMONITOR_RET_OKWITHWARN; } int PacketSource_Madwifi::AutotypeProbe(string in_device) { // See if it looks like a madwifi-ng device if we can't match anything else vector mwngvaps; if (madwifing_list_vaps(in_device.c_str(), &mwngvaps) > 0) { type = "madwifi"; return 1; } return 0; } PacketSource_Wrt54Prism::PacketSource_Wrt54Prism(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Wext(in_globalreg, in_interface, in_opts) { // We get FCS bytes SetFCSBytes(4); } int PacketSource_Wrt54Prism::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("wrt54prism", this, "IEEE80211b", 1); return 1; } int PacketSource_Wrt54Prism::OpenSource() { error = 0; // Store the interface string realsrc = interface; // Fake the prism0 interface interface = "prism0"; // Open using prism0 int ret = PacketSource_Wext::OpenSource(); // Restore interface = realsrc; if (ret < 0) return ret; // Anything but windows and linux #if defined (SYS_OPENBSD) || defined(SYS_NETBSD) || defined(SYS_FREEBSD) \ || defined(SYS_DARWIN) // Set the DLT in the order of what we want least, since the last one we // set will stick pcap_set_datalink(pd, DLT_IEEE802_11); pcap_set_datalink(pd, DLT_IEEE802_11_RADIO_AVS); pcap_set_datalink(pd, DLT_IEEE802_11_RADIO); // Hack to re-enable promisc mode since changing the DLT seems to make it // drop it on some bsd pcap implementations ioctl(pcap_get_selectable_fd(pd), BIOCPROMISC, NULL); // Hack to set the fd to IOIMMEDIATE, to solve problems with select() on bpf // devices on BSD int v = 1; ioctl(pcap_get_selectable_fd(pd), BIOCIMMEDIATE, &v); #endif if (DatalinkType() < 0) { if (pd != NULL) pcap_close(pd); return -1; } return 1; } #endif kismet-2013-03-R1b/util.h0000664000175000017500000001674312124602454014614 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __UTIL_H__ #define __UTIL_H__ #include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ieee float struct for a 64bit float for serialization typedef struct { uint64_t mantissa:52 __attribute__ ((packed)); uint64_t exponent:11 __attribute__ ((packed)); uint64_t sign:1 __attribute__ ((packed)); } ieee_64_float_t; typedef struct { unsigned int mantissal:32; unsigned int mantissah:20; unsigned int exponent:11; unsigned int sign:1; } ieee_double_t; typedef struct { unsigned int mantissal:32; unsigned int mantissah:32; unsigned int exponent:15; unsigned int sign:1; unsigned int empty:16; } ieee_long_double_t; // Munge a string to characters safe for calling in a shell void MungeToShell(char *in_data, int max); string MungeToShell(string in_data); string MungeToPrintable(const char *in_data, int max, int nullterm); string MungeToPrintable(string in_str); string StrLower(string in_str); string StrUpper(string in_str); string StrStrip(string in_str); string StrPrintable(string in_str); string AlignString(string in_txt, char in_spacer, int in_align, int in_width); int HexStrToUint8(string in_str, uint8_t *in_buf, int in_buflen); string HexStrFromUint8(uint8_t *in_buf, int in_buflen); template class NtoString { public: NtoString(t in_n, int in_precision = 0, int in_hex = 0) { ostringstream osstr; if (in_hex) osstr << hex; if (in_precision) osstr << setprecision(in_precision) << fixed; osstr << in_n; s = osstr.str(); } string Str() { return s; } string s; }; #define IntToString(I) NtoString((I)).Str() #define HexIntToString(I) NtoString((I), 0, 1).Str() #define LongIntToString(L) NtoString((L)).Str() #define FloatToString(F) NtoString((F)).Str() void SubtractTimeval(struct timeval *in_tv1, struct timeval *in_tv2, struct timeval *out_tv); // Generic options pair struct opt_pair { string opt; string val; int quoted; }; // Generic option handlers string FetchOpt(string in_key, vector *in_vec); int FetchOptBoolean(string in_key, vector *in_vec, int dvalue); vector FetchOptVec(string in_key, vector *in_vec); int StringToOpts(string in_line, string in_sep, vector *in_vec); void AddOptToOpts(string opt, string val, vector *in_vec); void ReplaceAllOpts(string opt, string val, vector *in_vec); // String compare, 1 true 0 false -1 unknown, or default value as provided int StringToBool(string s, int dvalue = -1); // Append to a string, with a delimiter if applicable string StringAppend(string s, string a, string d = " "); int XtoI(char x); int Hex2UChar(unsigned char *in_hex, unsigned char *in_chr); vector StrTokenize(string in_str, string in_split, int return_partial = 1); // 'smart' tokenizeing with start/end positions struct smart_word_token { string word; size_t begin; size_t end; smart_word_token& operator= (const smart_word_token& op) { word = op.word; begin = op.begin; end = op.end; return *this; } }; vector BaseStrTokenize(string in_str, string in_split, string in_quote); vector NetStrTokenize(string in_str, string in_split, int return_partial = 1); // Simplified quoted string tokenizer, expects " ' to start at the beginning // of the token, no abc"def ghi" vector QuoteStrTokenize(string in_str, string in_split); int TokenNullJoin(string *ret_str, const char **in_list); string InLineWrap(string in_txt, unsigned int in_hdr_len, unsigned int in_max_len); vector LineWrap(string in_txt, unsigned int in_hdr_len, unsigned int in_maxlen); vector Str2IntVec(string in_text); int IsBlank(const char *s); // Clean up XML and CSV data for output string SanitizeXML(string); string SanitizeCSV(string); void Float2Pair(float in_float, int16_t *primary, int64_t *mantissa); float Pair2Float(int16_t primary, int64_t mantissa); // Convert a standard channel to a frequency int ChanToFreq(int in_chan); int FreqToChan(int in_freq); // Convert an IEEE beacon rate to an integer # of beacons per second unsigned int Ieee80211Interval2NSecs(int in_rate); // Run a system command and return the error code. Caller is responsible // for security. Does not fork out int RunSysCmd(char *in_cmd); // Fork and exec a syscmd, return the pid of the new process pid_t ExecSysCmd(char *in_cmd); #ifdef SYS_LINUX int FetchSysLoadAvg(uint8_t *in_avgmaj, uint8_t *in_avgmin); #endif // Adler-32 checksum, derived from rsync, adler-32 uint32_t Adler32Checksum(const char *buf1, int len); // 802.11 checksum functions, derived from the BBN USRP 802.11 code #define IEEE_802_3_CRC32_POLY 0xEDB88320 unsigned int update_crc32_80211(unsigned int crc, const unsigned char *data, int len, unsigned int poly); void crc32_init_table_80211(unsigned int *crc32_table); unsigned int crc32_le_80211(unsigned int *crc32_table, const unsigned char *buf, int len); // Proftpd process title manipulation functions void init_proc_title(int argc, char *argv[], char *envp[]); void set_proc_title(const char *fmt, ...); // Simple lexer for "advanced" filter stuff and other tools #define _kis_lex_none 0 #define _kis_lex_string 1 #define _kis_lex_quotestring 2 #define _kis_lex_popen 3 #define _kis_lex_pclose 4 #define _kis_lex_negate 5 #define _kis_lex_delim 6 typedef struct { int type; string data; } _kis_lex_rec; list<_kis_lex_rec> LexString(string in_line, string& errstr); #define LAT_CONVERSION_FACTOR 10000000 #define LON_CONVERSION_FACTOR 10000000 #define ALT_CONVERSION_FACTOR 1000 /* PPI-Geolocation tag conversion routines. (from lib_ppi_geotag) * Floating point numbers are stored on disk in a handful of fixed-point formats (fixedX_Y) * designed to preserve the appropriate amount of precision vs range. These functions convert * the fixedX_Y fixed point values into 'native' doubles for displaying. * Documentation on these formats can be found in the PPI-GEOLOCATION specification */ double fixed3_7_to_double(u_int32_t in); double fixed3_6_to_double(u_int32_t in); double fixed6_4_to_double(u_int32_t in); u_int32_t double_to_fixed3_7(double in); u_int32_t double_to_fixed3_6(double in); u_int32_t double_to_fixed6_4(double in); /* * Some values are encoded as 32-bit unsigned nano-second counters. * Usually we want to display these values as doubles. */ double ns_to_double(u_int32_t in); u_int32_t double_to_ns(double in); #endif kismet-2013-03-R1b/dumpfile_gpsxml.h0000664000175000017500000000255012124602454017025 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_GPSXML_H__ #define __DUMPFILE_GPSXML_H__ #include "config.h" #include #include #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "dumpfile.h" // Hook for grabbing packets int dumpfilegpsxml_chain_hook(CHAINCALL_PARMS); // GPSXML point logger class Dumpfile_Gpsxml : public Dumpfile { public: Dumpfile_Gpsxml(); Dumpfile_Gpsxml(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Gpsxml(); virtual int chain_handler(kis_packet *in_pack); virtual int Flush(); protected: FILE *xmlfile; time_t last_track; }; #endif /* __dump... */ kismet-2013-03-R1b/packetsource_ipwlive.h0000664000175000017500000000527312124602454020062 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * WEXT is the linux wireless extensions tools subset of pcap capture devices. * Anything controlled by the standard wireless extensions will live here. */ #ifndef __PACKETSOURCE_IPWLIVE_H__ #define __PACKETSOURCE_IPWLIVE_H__ #include "config.h" #if (defined(HAVE_LIBPCAP) && defined(SYS_LINUX) && defined(HAVE_LINUX_WIRELESS)) #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #include "ifcontrol.h" #include "iwcontrol.h" #ifdef HAVE_LINUX_SYS_RADIOTAP #include #endif #ifdef HAVE_LOCALRADIOTAP #include "local_ieee80211_radiotap.h" #endif #define USE_PACKETSOURCE_IPWLIVE // Another pcap variant: ipwlivetap, for doing rfmon+managed // For ipw2200 and ipw3945 class PacketSource_Ipwlive : public PacketSource_Pcap { public: // HANDLED PACKET SOURCES: // ipwlivetap PacketSource_Ipwlive() { fprintf(stderr, "FATAL OOPS: Packetsource_Ipwlive() called\n"); exit(1); } PacketSource_Ipwlive(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Ipwlive(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_Ipwlive(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { // foo } virtual ~PacketSource_Ipwlive() { } // Should be, something can override if it needs virtual int FetchChannelCapable() { return 0; } // Generic-level functions virtual int EnableMonitor(); virtual int DisableMonitor(); virtual int SetChannel(unsigned int in_ch); virtual int FetchChannel(); protected: virtual void FetchRadioData(kis_packet *in_packet) { }; }; #endif /* have_libpcap && sys_linux */ #endif kismet-2013-03-R1b/docs/0000775000175000017500000000000012124602454014403 5ustar dragorndragornkismet-2013-03-R1b/docs/DEVEL.client0000664000175000017500000000772012124602454016450 0ustar dragorndragornClient/Server Protocol The Kismet client/server protocol has evolved over time, but is finally (as of this writing) at a stable state. This new method of communication allows a client to request only the protocols which are of interest, AND to control the fields and field order that these protocols are sent with. This removes the disruption the addition of new protocols and new tracking data caused to independent clients. The basics of the protocol are as follows: The server->client protocol consists of one-line statements of the format: *{HEADER}: {Data} {HEADER} denotes the type of protocol, ie KISMET, NETWORK, TIME, etc. {Data} denotes the free-form data for this protocol. Multi-field data is seperated with spaces. Any data field that may contain spaces is buffered by \001{Field}\001. This buffering is not used for protocols such as STATUS which return only a single field. The client->server commands consist of one-line statements of the format: !{ID} {COMMAND} {Options} {ID} is a unique numerical identifier (timestamp is often used) which is used by the server to return an error condition for a specific command. If {ID} is set to 0, no ACK is returned. {COMMAND} is the command to be run (ie, ENABLE, REMOVE, CAPABILITY) {Options} are the options for that command. Basic client support: The server expects every client to handle the following basic protocols, and automatically enables them for that client at connect time. All other protocols must be specifically request. *KISMET: {Version} {Start time} {Server name} {Build Revision} Initial identifier *ACK: {Command ID} Acknowledgement that a command was processed. If your client doesn't care about acknowledgements, this can be ignored or commands can be sent with an ID of 0. *ERROR: {String} Error response for an invalid request. The simplest way to handle this is to print it as a status message. More advanced handling can be added at your discretion. *PROTOCOLS: {Comma-delimited string of supported protocols} List of protocols this server supports *CAPABILITY: {Protocol} {Comma-delimited string of fields} Capability of a specific protocol *TERMINATE: {String} Server termination *TIME: {Current time} Current server time in seconds since the epoch The server supports the following commands: !{ID} CAPABILITY {Protocol} Request that a *CAPABILITY line be sent for the protocol !{ID} ENABLE {Protocol} {Comma-delimited string of requested fields}|{*} Enable sending a protocol with the requested field order. * enables all fields in the default order. !{ID} REMOVE {Protocol} Stop sending a protocol !{ID} PAUSE Pause the packet sources !{ID} RESUME Resume capturing from the packet sources !{ID} LISTWEPKEYS Lists WEP decryption keys if the server allows this. !{ID} ADDWEPKEY {bssid},{hex key} Add a WEP decryption key for the given BSSID. !{ID} DELWEPKEY {bssid} Remove the WEP key for a give BSSID. An example session: Connected to localhost. Escape character is '^]'. KISMET: 2.7.1 1038236534 `"Gir"` 20021118101152 *PROTOCOLS: KISMET,ERROR,PROTOCOLS,CAPABILITY,TERMINATE,TIME,NETWORK,CLIENT,GPS,INFO,REMOVE,STATUS,PACKET,ALERT,STRING !1234 CAPABILITY NETWORK *ACK: 1234 *CAPABILITY: NETWORK bssid,type,ssid,beaconinfo,llcpackets,datapackets,cryptpackets,weakpackets,channel,wep,firsttime,lasttime,atype,rangeip,gpsfixed,minlat,minlon,minalt,minspd,maxlat,maxlon,maxalt,maxspd,octets,cloaked,beaconrate,maxrate,manufkey,manufscore,quality,signal,noise,bestquality,bestsignal,bestnoise,bestlat,bestlon,bestalt,agglat,agglon,aggalt,aggpoints !1235 ENABLE NETWORK bssid,type,ssid *ACK: 1235 *NETWORK: 00:40:96:55:A2:72 0 `p@thf1nd3r` *NETWORK: 00:A0:F8:41:3C:DD 0 `KrullNet1` ... PROTOCOL and CAPABILITY processing is left to the discretion of the client author - they may be ignored with the understanding that a request for an unknown protocol or an unknown field will result in an error, or they can be processed to verify that the server accepts all the desired fields. kismet-2013-03-R1b/docs/README.newcore0000664000175000017500000003464412124602454016737 0ustar dragorndragornKismet Newcore The existing Kismet codebase has grown from its beginnings. While it works, generally, it has been grown, not designed, and has numerous quirks and poorly implemented parts. The newcore branch of Kismet is a nearly complete rewrite of the entire codebase, focusing on design, maintainablity, and modular code. A major goal of the rewrite is to allow a plugin architecture, which is well under way. After nearly a year of development, the newcore codebase is finally functional. Now that it is standing on its own, development will go much more quickly. Major modules are still missing from the code, however they are being filled in rapidly. Like any major rewrite, there will be growing pains as platform or interface-specific components are put back into action. Once newcore has reached an equivalent level of functionality with the stable code branch, it will replace the existing Kismet codebase. SECURITY MODEL Kismet now uses a suid-root group-exec-only binary configure interfaces, similar to how wireshark now brokers access. When Kismet is compiled and installed with suidroot, the kismet_server and kismet_drone processes are installed as normal with no suid capabilities. Early in the execution process, kismet_capture is fork-exec'd to provide a structured IPC interface to a root control process. If Kismet is not compiled with suidroot or if it is launched as root, it will not launch the kismet_capture process and will remain running as root. This security model is meant to make it easier for distro package maintainers and users, and removes the suid_user element from the config file. DEVELOPING IN NEWCORE Some disjointed comments about the design... Everything in newcore is (primarily) a fully self-contained module. The module can do its own config file parsing, command line argument parsing, etc. Modules can (and should) register their own packet components and their own network protocols. The core packet model is the "packet chain". Packets are created and then injected into the chain. As they pass through the chain, new components can be added to them; For example, most packets will have a raw link data component, a 802.11 raw component, a parsed 802.11 information block, and a gps data component. The base event loop is driven by the core single select() and the timetracker event module. All modules which need to participate in the select() event loop should be derived from the Pollable class and register themselves with the global polling system. Every module should connect to the GlobalRegistry. This is a large super-class of variables which takes the place of a messy pile of globals. Non-mainline modules can register new tracked components with the global registry to share between classes. The globalreg functions as the main tracking system for injecting messages, accessing runtime configuration, and communicating with other modules. The messagebus is a common system for sending information to the user. A text string injected into the messagebus carries flags to indicate the type of message. Subscribers to the messagebus can then display the message, log it to a file, queue it for output to stdout on exit, etc. NEWCORE EXECUTION PATHS For anyone interested in developing modules or plugins, it's important to know how the kismet engine actually works, now: * Startup - Allocate global registry - Initialize argc/argv/env variables - Initialize messagebus and message clients (stdout, fatal) - Launch forked root control process (if uid != 0) - initialize timetracker - Parse command line options - Parse config file - Initialize network framework - Initialize plugin framework - Initialize alert framework - Initialize capture source framework - Activate root plugins - Process configured capture sources - Register tun/tap dumpfile - Spawn root control IPC child - Activate network framework - Scan user plugins - Initialize builtin packet dissectors - Activate sound and speech IPC processes - Activate gpsd client - Activate network tracker framework - Activate dump files - Activate timer events - Give plugins a final chance to activate - Activate packet sources - Begin main loop * Main loop - Aggregate fd_sets from all subsystems registered with Pollable - Select() - Tick the timer framework - Poll all subsystems registered with Pollable() EXAMPLES Currently one of the best examples of the newcore design is the GPS client module, gpsdclient.[h|cc]. It excercises many of the new methods. NETWORK TRACKING Network tracking is basically the same as it was before, however some things have been made more explicit: * All networks now have at least one client. The network itself is a client of itself. This handles many weird discrepencies in the old model about how client data was different from network data, how IPs were calculated, etc. * Network totals are still tracked realtime. This is much cheaper than iterating over the clients in a network shell. * Network numbers must be recalculated when moving a client to another network. subtract all the totals of client1 from net1 and add them to net2 * The kisclient will be responsible for moving clients between networks on the client end of things, but doesn't need to be smart enough to move packet totals -- the new packet total for the network shell will be pushed in the NETWORK update. PLUGIN ARCHITECTURE Plugins are scary things. They can do basically anything to you. Be careful what you load! Root plugins: Plugins that load as root before the privdrop must be in the system plugin directory (/install-prefix/lib/kismet/). That directory must be owned by root:root. The directory must not be writeable by anyone else (mode 755 or more restrictive). The plugin must be owned by root:root, and not be writeable by anyone else (755 or more restrictive). Finally, the plugin MUST be specified in the kismet.conf config on a 'rootplugin=foo.so' line. User plugins: Anything found in a plugin directory after the privdrop, that wasn't loaded as root, is probed and loaded. Plugin directories are '/install-prefix/lib/kismet/' and 'userconfig/plugins/' (typically ~/.kismet/plugins). Security mentality: Root plugins are super-dangerous. We can't keep the user from loading one, but we can make sure that other users on the system can't corrupt it, and we can make sure only ones actively approved are loaded during startup. Plugins must be enabled in the config file! Plugins are expected to have 1 exported extern "C" function, and respond to register/unregister events appropriately. Look at the example plugin for more info. The plugin registrant is called many times during load, until it returns a value that indicates total failure or success. A plugin can look at the globalregistry pointers for standard system components to determine if the plugin is able to load yet. If it isn't, it should return 0 and it will be asked again later. Plugins are responsible for adding their own callbacks to the system components, and for removing them cleanly on request. Plugins have access to any system component that Kismet itself can access, which gives them extroadinary power. Things to remember about C++ and plugins: * Don't do things that would cause the kismet_server code to new an object. Use a helper function. This should be pretty easy to maintain since it's all callbacks that insert objects into kismet_server components anyway * All classes used in a plugin must have virtual destructors. All their parents must have virtual destructors. Even if they don't actually need one. If you find a kismet core class you need to use in a plugin, tell me, and I'll make sure it's got virtual destructors. Documentation on the system components and APIs will be forthcoming. DRONE PROTOCOL The newcore drone protocol is similar to the original remote capture drone protocol from Kismet, however it is different in several key ways at not backwards compatible with the original drone protocol. The Newcore-drone protocol is designed to be forward- and backward-compatible with itself, so that different versions of the drone client and drone server can communicate with eachother, as completely as their protocol implementations allow. While not exactly encouraged, the more robust newcore protocol will allow for third-party drone clients to participate as well. Frames with dynamic components such as captured_packet are split into sub-frames and combined with bitfields to indicate what data is present. Frames with an unknown cmdnum can be ignored. New frame elements must be added AFTER known frame elements, so that clients can parse the known bitfield elements. Clients are assumed to know the size of each element in the bitfield. The length field in each type and subtype is used to skip unknown data once known data has been read. All integers are in network-endian format. uint8s are avoided to prevent struct packing problems on some platforms. Doubles are extracted into mantissa, exponent, and sign components and each component is translated to network endian before transmission. Basic frame formats: drone_packet sentinel cmdnum/packet type data len [... data ...] capture_packet (placed in drone_packet->data) content bitmap (radio|gps|ieee|rawdata) packet data offset (to head of packet) [... packed data of all headers indicated in bitfield, followed by raw frame ...] (optional if radio header present in content bitmap) radio header len radio header bitmap (accuracy|channel|signal...datarate) radio accuracy radio channel radio signal radio noise radio carrier radio encoding radio datarate [... future expansion by adding to radio header bitmap ...] (optional if gps header present in content bitmap) gps header len gps header bitmap gps fix gps lat ... gps heading [... future expansion by adding to gps header bitmap ...] (optional if IEEEpacket set) eight11 header len (goes to start of packet) eight11 header bitmap packet len error tv_sec tv_usec [... future expansion by adding to gps header bitmap ...] [ packet data ] PACKETSOURCES A packetsource is the os and driver specific code used to get packets from whatever, and turn them into something Kismet can use. A packetsource need not be a lot of code - the BSD radtiotap packetsource is only 600 lines of code. The packetsource defines everything needed to turn packets into the normal format used by Kismet and to control the device, including setting monitor mode, caching former values, resetting the card to the previous operational mode, and changing channels. Packetsources have a globally unique UUID. When multiple servers use a drone source, they will all get the same UUID and can use it to correlate data. How the KisPacketSource class works: All packetsources are subclassed from the KisPacketSource class. Sometimes, it makes sense to nest classes two or three deep below KisPacketSource. Normally this would be a bad idea, but it seems to make the most sense here. Instantatiations of a KisPacketSource have two types, weak and strong. Weak packetsources never themselves become strong packetsources, but are used to register the actual types with the packetsourcetracker, test the autoprobe function to identify types, and to create the actual strong packet source. Weak instances can expect globalregistry to be available, but not much else. They should not try to open any devices or capture packets (and packetsourcetracker will never as them to). Strong instances of a KisPacketSource are created with the CreateSource(...) function in the weak instance. Strong sources are given the globalregistry, type string, interface, and name. Strong sources are expected to handle channel control, monitor control, etc. Things to keep in mind making your own: Options on the source line are passed via the in_opts vector Registering types gives the packetsourcetracker a method to call your CreateSource. You should register all the types you intend to provide. Kismet uses a #define to indicate to kismet_server.cc and kismet_drone.cc that an instance of your source should be bootstrapped into the packetsourcetracker. Define something like USE_PACKETSOURCE_FOO and add it to the #ifdefs in main(). This prevents cluttering the main function with convoluted ifdef tests -- put those in your header before you define USE_PACKETSOURCE_... If you don't need root to control the source, don't specify it on the proto registration - it'll only create overhead. Most kismet sources support a grace period when setting the channel, incase a card has a momentary hiccup. I usually use 5 consecutive errors as an indication it's really broken and don't return a fail condition on SetChannel until I hit that. The autotypeprobe function will be called with nothing more than a string indicating the device. It's up to you to try to identify it. Sysfs is usually a good way to go on this. On Darwin, it's identified by the interface name. If you can get the MAC address of the source, it wouldn't be a bad thing to re-seed the UUID using it. packetsource_wext does this on Linux. The packetsourcetracker won't expect the UUID until after EnableMonitor() is called. NEWCORE SOURCE CONTROL KISMET COMMANDS Lock to channel: CHANLOCK uuid chnum Hop across channel list: CHANHOP uuid Set channel list: CHANSEQ uuid ch1,ch2,ch3,ch4 Add a new source: ADDSOURCE interface:options Delete a source: DELSOURCE uuid NEWCORE SAVE STATE Kismet now supports resuming from a previous state. The 'runstate' dump file type logs the important current states every time dump files are logged. To write the current state along with other dumpfiles, add 'runstate' to your logtypes. To resume a previous runstate, use '--resume' or '-r' on the runstate file. Runstates should be resumed under the same config file and options as they were created under. Warnings will be issued if the config file has changed. For consistency, only dumpfiles enabled when the runstate was created are enabled when a runstate is resumed. kismet-2013-03-R1b/docs/devel-wiki-docs/0000775000175000017500000000000012124602454017371 5ustar dragorndragornkismet-2013-03-R1b/docs/devel-wiki-docs/IndeX.wiki0000664000175000017500000000172512124602454021272 0ustar dragorndragorn= Kismet Development Wiki = == What you'll find == This wiki is for holding information about writing plugins and other ways to interact with the Kismet source. == About the Wiki == This Wiki was created using Wicked, the VIM wiki plugin. It can be exported to other formats using the Wicked tools (which don't require VIM) available at http://www.redsheep.de/wiked/ . == Core code components == Kismet is divided into multiple, mostly self-contained subsystems. To hook into the inner workings, you must register components with each. AlertTracker : IDS alert system GlobalRegistry : Global registry of core components KisNetFramework : Kismet server/client protocol system MessageBus : Text message dispatch system NetTracker : Network classifier and tracker PacketChain : Packet traversal PacketsourceTracker : Capture source system TimeTracker : Event system ConfigFile : Configuration file reading NetworkSubsystem : Networking subsystem classes kismet-2013-03-R1b/docs/devel-wiki-docs/PacketChain.wiki0000664000175000017500000000502312124602454022430 0ustar dragorndragorn=PacketChain= == PacketChain basics == The PacketChain is the core mechanism by which packets make their way through Kismet. Packets are inserted into the chain by capture devices, and may have any number of custom attributes attached to them. The base stages of the PacketChain are: * GENESIS * POST-CAPTURE * PROTO-DISSECTION * FILTER * DECRYPT * DATA-DISSECTION * CLASSIFICATION * LOGGING * DESTRUCTION == Packet components/attributes == Packet components are subclasses of the stub ``packet_component''. A packet component can contain any information about a packet. A packet may have many components or it may have only one or two. Builtin components include the raw captured data, the data modified to fit the 80211 standard, decrypted data, 80211 layer2 signal information, gps information, and more. For a component to be used on a packet, it must be registered. Registering a component gives an integer reference to that component type. Manipulating components in a kis_packet: kis_packet *foo; ... foo->insert(mycompref, mycomp); ... foo->fetch(globalreg->pcr_gps_ref); // NULL if no gps data ... foo->erase(mycompref); Registering and unregistering packet components from the Packetchain: int RegisterPacketComponent(string in_component); An integer value for fast-reference to the added packet type is returned. The string may be used by other components in the future to fetch a reference to the component id. int RemovePacketComponent(int in_id); Unregister a component. == Packetchain packet genesis == Packet creation is normally done only during genesis from a capture source. Creating packets: kis_packet *GeneratePacket(); Generate a packet and return it to the caller for genesis components. int ProcessPacket(kis_packet *in_pack); Inject a packet into the chain. == Chain handlers == To be part of the packet chain and process packets, you must register a packet handler: int RegisterHandler(pc_callback in_cb, void *in_aux, int in_chain, int in_prio); The handler consists of a callback function which will be used to trigger your handler, a pointer to arbitrary auxillary data, the portion of the chain the handler will be attached to, and the priority. Priorities less than zero are reserved for Kismet internal handlers, and replacing them will likely lead to a number of problems. A chain handler receives the packet with all components currently available. It may do any processing it wishes on the packet, and add components to it before releasing it. ---- related: IndeX kismet-2013-03-R1b/docs/devel-wiki-docs/AlertTracker.wiki0000664000175000017500000000155312124602454022645 0ustar dragorndragorn=AlertTracker= AlertTracker is responsible for defining IDS alerts, throttling alert rates based on configuration, and other alert duties. Alerts are created with: int RegisterAlert(const char *in_header, alert_time_unit in_unit, int in_rate, int in_burst); The returned integer is the reference value for the created alert or (-1) for failure. This reference value is needed for other alert funtions. ``in_header'' is the name of the alert sent in the *ALERT protocol. Rate limiting should be read from the ConfigFile. Alerts are raised with: int RaiseAlert(int in_ref, mac_addr bssid, mac_addr source, mac_addr dest, mac_addr other, int in_channel, string in_text); If generating a given alert is a time consuming task, a quick test can be performed to see if the alert would be sent: int PotentialAlert(int in_ref); ---- related: IndeX kismet-2013-03-R1b/docs/devel-wiki-docs/tags0000664000175000017500000000170712124602454020257 0ustar dragorndragornAlertTracker AlertTracker.wiki 1 ConfigFile /home/dragorn/.vim/tools/unknown.wiki 1 GeneratePacket /home/dragorn/.vim/tools/unknown.wiki 1 GlobalRegistry /home/dragorn/.vim/tools/unknown.wiki 1 IndeX IndeX.wiki 1 KisNetFramework /home/dragorn/.vim/tools/unknown.wiki 1 MessageBus /home/dragorn/.vim/tools/unknown.wiki 1 NetTracker /home/dragorn/.vim/tools/unknown.wiki 1 NetworkSubsystem /home/dragorn/.vim/tools/unknown.wiki 1 PacketChain PacketChain.wiki 1 PacketsourceTracker /home/dragorn/.vim/tools/unknown.wiki 1 PotentialAlert /home/dragorn/.vim/tools/unknown.wiki 1 ProcessPacket /home/dragorn/.vim/tools/unknown.wiki 1 RaiseAlert /home/dragorn/.vim/tools/unknown.wiki 1 RegisterAlert /home/dragorn/.vim/tools/unknown.wiki 1 RegisterHandler /home/dragorn/.vim/tools/unknown.wiki 1 RegisterPacketComponent /home/dragorn/.vim/tools/unknown.wiki 1 RemovePacketComponent /home/dragorn/.vim/tools/unknown.wiki 1 TimeTracker /home/dragorn/.vim/tools/unknown.wiki 1 kismet-2013-03-R1b/kismet_server.h0000664000175000017500000000307312124602454016511 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISMET_SERVER_H__ #define __KISMET_SERVER_H__ #include "config.h" #include #include #include "tcpserver.h" #include "netracker.h" void WriteDatafiles(int in_shutdown); void CatchShutdown(int sig); int Usage(char *argv); int NetWriteStatus(const char *in_status); void NetWriteInfo(); int SayText(string in_text); int PlaySound(string in_sound); void SpeechHandler(int *fds, const char *player); void SoundHandler(int *fds, const char *player, map soundmap); void ProtocolAlertEnable(int in_fd); void ProtocolNetworkEnable(int in_fd); void ProtocolClientEnable(int in_fd); void KisLocalAlert(const char *in_text); void KisLocalStatus(const char *in_status); void KisLocalNewnet(const wireless_network *in_net); void KisLocalNewclient(const wireless_client *in_cli, const wireless_network *in_net); #endif kismet-2013-03-R1b/kis_droneframe.cc0000664000175000017500000007416112124602454016763 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "util.h" #include "endian_magic.h" #include "configfile.h" #include "packet.h" #include "packetsource.h" #include "packetchain.h" #include "kis_droneframe.h" #include "tcpserver.h" #include "getopt.h" #include "gpscore.h" #include "version.h" #include "packetsourcetracker.h" void KisDroneframe_MessageClient::ProcessMessage(string in_msg, int in_flags) { string msg; if ((in_flags & MSGFLAG_LOCAL) || (in_flags & MSGFLAG_ALERT)) return; ((KisDroneFramework *) auxptr)->SendAllText(in_msg, in_flags); } int kisdrone_chain_hook(CHAINCALL_PARMS) { return ((KisDroneFramework *) auxdata)->chain_handler(in_pack); } int kisdrone_time_hook(TIMEEVENT_PARMS) { return ((KisDroneFramework *) parm)->time_handler(); } int dronecmd_channelset_hook(DRONE_CMD_PARMS) { return ((KisDroneFramework *) auxptr)->channel_handler(data); } void drone_pst_sourceact_hook(SOURCEACT_PARMS) { ((KisDroneFramework *) auxptr)->sourceact_handler(src, action, flags); } void KisDroneFramework::Usage(char *name) { printf(" *** Kismet Remote Drone Options ***\n"); printf(" --drone-listen Override Kismet drone listen options\n"); } KisDroneFramework::KisDroneFramework() { fprintf(stderr, "FATAL OOPS: KisDroneFramework() called with no globalreg\n"); exit(1); } KisDroneFramework::KisDroneFramework(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; netserver = NULL; int port = 0, maxcli = 0; char srv_proto[11], srv_bindhost[129]; TcpServer *tcpsrv; string listenline; valid = 0; // Sanity check for timetracker if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: KisDroneFramework called without timetracker\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: KisDroneFramework called without " "kismet_config\n"); exit(1); } if (globalreg->messagebus == NULL) { fprintf(stderr, "FATAL OOPS: KisDroneFramework called without messagebus\n"); exit(1); } if (globalreg->sourcetracker == NULL) { fprintf(stderr, "FATAL OOPS: KisDroneFramework called without " "packetsourcetracker\n"); exit(1); } if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: KisDroneFramework called without packetchain\n"); exit(1); } int dlc = globalreg->getopt_long_num++; // Commandline stuff static struct option droneframe_long_options[] = { { "drone-listen", required_argument, 0, dlc }, { 0, 0, 0, 0 } }; int option_idx = 0; optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-", droneframe_long_options, &option_idx); if (r < 0) break; if (r == dlc) { listenline = string(optarg); } } if (listenline.length() == 0 && (listenline = globalreg->kismet_config->FetchOpt("dronelisten")) == "") { _MSG("No 'dronelisten' config line and no command line drone-listen " "argument given, Kismet drone server will not be enabled.", MSGFLAG_INFO); server_type = -1; return; } if (sscanf(listenline.c_str(), "%10[^:]://%128[^:]:%d", srv_proto, srv_bindhost, &port) != 3) { _MSG("Malformed 'dronelisten' config line provided for the Kismet " "drone server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("dronemaxclients") == "") { _MSG("No 'dronemaxclients' config line defined for the Kismet drone " "server, defaulting to 5 clients.", MSGFLAG_INFO); maxcli = 5; } else if (sscanf(globalreg->kismet_config->FetchOpt("dronemaxclients").c_str(), "%d", &maxcli) != 1) { _MSG("Malformed 'dronemaxclients' config line provided for the Kismet" "drone server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("droneallowedhosts") == "") { _MSG("No 'droneallowedhosts' config line defined for the Kismet drone " "server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } // We only know how to set up a tcp server if (strncasecmp(srv_proto, "tcp", 10) == 0) { tcpsrv = new TcpServer(globalreg); tcpsrv->SetupServer(port, maxcli, srv_bindhost, globalreg->kismet_config->FetchOpt("droneallowedhosts")); netserver = tcpsrv; server_type = 0; } else { server_type = -1; _MSG("Invalid protocol '" + string(srv_proto) + "' in 'dronelisten' for the " "Kismet drone server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } if (globalreg->kismet_config->FetchOpt("droneringlen") != "") { int rl; if (sscanf(globalreg->kismet_config->FetchOpt("droneringlen").c_str(), "%d", &rl) != 1) { _MSG("Invalid value in 'droneringlen' for the Kismet dorne server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Setting drone connection buffer to " + globalreg->kismet_config->FetchOpt("droneringlen") + " bytes", MSGFLAG_INFO); tcpsrv->SetRingSize(rl); } // Create the message bus attachment to forward messages to the client kisdrone_msgcli = new KisDroneframe_MessageClient(globalreg, this); globalreg->messagebus->RegisterClient(kisdrone_msgcli, MSGFLAG_ALL); // Register the packet handler globalreg->packetchain->RegisterHandler(&kisdrone_chain_hook, this, CHAINPOS_POSTCAP, 100); // Register the source action handler globalreg->sourcetracker->RegisterSourceActCallback(&drone_pst_sourceact_hook, (void *) this); // Event trigger eventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &kisdrone_time_hook, (void *) this); // Register the internals so nothing else can, but they just get nulls RegisterDroneCmd(DRONE_CMDNUM_NULL, NULL, this); RegisterDroneCmd(DRONE_CMDNUM_HELO, NULL, this); RegisterDroneCmd(DRONE_CMDNUM_STRING, NULL, this); RegisterDroneCmd(DRONE_CMDNUM_CAPPACKET, NULL, this); RegisterDroneCmd(DRONE_CMDNUM_CHANNELSET, dronecmd_channelset_hook, this); RegisterDroneCmd(DRONE_CMDNUM_SOURCE, NULL, this); valid = 1; } KisDroneFramework::~KisDroneFramework() { // Unregister the source action globalreg->sourcetracker->RemoveSourceActCallback(&drone_pst_sourceact_hook); if (globalreg != NULL && globalreg->messagebus != NULL) { globalreg->messagebus->RemoveClient(kisdrone_msgcli); } if (eventid >= 0) { globalreg->timetracker->RemoveTimer(eventid); } } int KisDroneFramework::Activate() { ostringstream osstr; if (server_type == -1) { _MSG("Kismet drone framework disabled, drone will not be activated.", MSGFLAG_INFO); return 0; } if (server_type != 0) { _MSG("KisDroneFramework unknown server type, something didn't " "initialize", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } if (netserver->EnableServer() < 0 || globalreg->fatal_condition) { _MSG("Failed to enable TCP listener for Kismet drone server", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } netserver->RegisterServerFramework(this); return 1; } int KisDroneFramework::Accept(int in_fd) { drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_helo_packet))); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_HELO); dpkt->data_len = kis_hton32(sizeof(drone_helo_packet)); drone_helo_packet *hpkt = (drone_helo_packet *) dpkt->data; hpkt->drone_version = kis_hton32(KIS_DRONE_VERSION); snprintf((char *) hpkt->kismet_version, 32, "%s-%s-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_TINY); snprintf((char *) hpkt->host_name, 32, "%s", globalreg->servername.c_str()); SendPacket(in_fd, dpkt); free(dpkt); // Send them all the sources vector *srcv = globalreg->sourcetracker->FetchSourceVec(); for (unsigned int x = 0; x < srcv->size(); x++) { SendSource(in_fd, (*srcv)[x], 0); SendChannels(in_fd, (*srcv)[x]); } return 1; } int KisDroneFramework::RegisterDroneCmd(uint32_t in_cmdid, DroneCmdCallback in_callback, void *in_aux) { ostringstream osstr; if (drone_cmd_map.find(in_cmdid) != drone_cmd_map.end()) { osstr << "Drone cannot register command id " << in_cmdid << " (" << hex << setprecision(4) << in_cmdid << ") because it already exists"; _MSG(osstr.str(), MSGFLAG_ERROR); return -1; } drone_cmd_rec *rec = new drone_cmd_rec; rec->auxptr = in_aux; rec->callback = in_callback; drone_cmd_map[in_cmdid] = rec; return 1; } int KisDroneFramework::RemoveDroneCmd(uint32_t in_cmdid) { map::iterator dcritr = drone_cmd_map.find(in_cmdid); if (dcritr == drone_cmd_map.end()) { return 0; } delete dcritr->second; drone_cmd_map.erase(dcritr); return 1; } int KisDroneFramework::ParseData(int in_fd) { int len, rlen; uint8_t *buf; ostringstream osstr; int pos = 0; int ret = 1; len = netserver->FetchReadLen(in_fd); // We don't care at all if we're less than the size of a drone frame if ((unsigned int) len < sizeof(drone_packet)) return 0; buf = new uint8_t[len + 1]; if (netserver->ReadData(in_fd, buf, len, &rlen) < 0) { osstr << "DroneFramework::ParseData failed to fetch data from " "client id " << in_fd; _MSG(osstr.str(), MSGFLAG_ERROR); delete[] buf; return -1; } if ((unsigned int) rlen < sizeof(drone_packet)) { delete[] buf; return 0; } while ((rlen - pos) >= (int) sizeof(drone_packet)) { drone_packet *dpkt = (drone_packet *) &(buf[pos]); if (kis_ntoh32(dpkt->sentinel) != DroneSentinel) { osstr << "DroneFramework::ParseData failed to find sentinel " "value in packet header, dropping connection to client " << in_fd; _MSG(osstr.str(), (MSGFLAG_ERROR | MSGFLAG_LOCAL)); delete[] buf; return -1; } unsigned int dplen = kis_ntoh32(dpkt->data_len); // Check for an incomplete packet in the buffer if (rlen - (int) pos < (int) (dplen + sizeof(drone_packet))) { delete[] buf; return 0; } // Take it out of the ring buffer netserver->MarkRead(in_fd, (dplen + sizeof(drone_packet))); unsigned int dcid = kis_ntoh32(dpkt->drone_cmdnum); // Do something with the command map::iterator dcritr = drone_cmd_map.find(dcid); if (dcritr == drone_cmd_map.end()) { osstr << "DroneFramework::ParseData got unknown packet type " << dcid << "(" << hex << setprecision(4) << dcid << ")"; _MSG(osstr.str(), (MSGFLAG_INFO | MSGFLAG_LOCAL)); } else { if (dcritr->second->callback == NULL) { osstr << "DroneFramework::ParseData throwing away packet of known " "type " << dcid << " (" << hex << setprecision(4) << dcid << ") " "with no handler"; _MSG(osstr.str(), (MSGFLAG_INFO | MSGFLAG_LOCAL)); } else { ret = (*dcritr->second->callback)(globalreg, dpkt, dcritr->second->auxptr); } } pos += dplen + sizeof(drone_packet); } delete[] buf; return ret; } int KisDroneFramework::KillConnection(int in_fd) { // Nothing to do here since we don't track per-client attributes return 1; } int KisDroneFramework::BufferDrained(int in_fd) { // Nothing to do here since we don't care about draining buffers since // we don't keep a client backlog return 1; } int KisDroneFramework::SendText(int in_cl, string in_text, int flags) { drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_string_packet) + in_text.length())); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_STRING); dpkt->data_len = kis_hton32(sizeof(drone_string_packet) + in_text.length()); drone_string_packet *spkt = (drone_string_packet *) dpkt->data; spkt->msg_flags = kis_hton32(flags); spkt->msg_len = kis_hton32(in_text.length()); memcpy(spkt->msg, in_text.c_str(), in_text.length()); int ret = 0; ret = SendPacket(in_cl, dpkt); free(dpkt); return ret; } int KisDroneFramework::SendAllText(string in_text, int flags) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendText(clvec[x], in_text, flags) > 0) nsent++; } return nsent; } int KisDroneFramework::SendSource(int in_cl, pst_packetsource *in_int, int invalid) { if (in_int->strong_source == NULL) return 0; drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_source_packet))); memset(dpkt, 0, sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_source_packet))); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_SOURCE); dpkt->data_len = kis_hton32(sizeof(drone_source_packet)); drone_source_packet *spkt = (drone_source_packet *) dpkt->data; spkt->source_hdr_len = kis_hton16(sizeof(drone_source_packet)); spkt->source_content_bitmap = kis_hton32(DRONEBIT(DRONE_SRC_UUID) | DRONEBIT(DRONE_SRC_INVALID) | DRONEBIT(DRONE_SRC_NAMESTR) | DRONEBIT(DRONE_SRC_INTSTR) | DRONEBIT(DRONE_SRC_TYPESTR) | DRONEBIT(DRONE_SRC_CHANHOP) | DRONEBIT(DRONE_SRC_CHANNELDWELL) | DRONEBIT(DRONE_SRC_CHANNELRATE)); DRONE_CONV_UUID(in_int->strong_source->FetchUUID(), &(spkt->uuid)); if (invalid) { spkt->invalidate = kis_hton16(1); } else { spkt->invalidate = kis_hton16(0); // Send the older style name/interface/type and recreate a source // line on the other end - saves us more effort than converting it to // a long ncsource style line, and we don't gain anything pulling // the local options into the drone mirror since they don't mean // anything there snprintf((char *) spkt->name_str, 16, "%s", in_int->strong_source->FetchName().c_str()); snprintf((char *) spkt->interface_str, 16, "%s", in_int->strong_source->FetchInterface().c_str()); snprintf((char *) spkt->type_str, 16, "%s", in_int->strong_source->FetchType().c_str()); if (in_int->channel_hop) spkt->channel_hop = 1; spkt->channel_dwell = kis_hton16(in_int->channel_dwell); spkt->channel_rate = kis_hton16(in_int->channel_rate); } int ret = 0; ret = SendPacket(in_cl, dpkt); free(dpkt); return ret; } int KisDroneFramework::SendAllSource(pst_packetsource *in_int, int invalid) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendSource(clvec[x], in_int, invalid) > 0) nsent++; } return nsent; } int KisDroneFramework::SendSourceReport(int in_cl, pst_packetsource *in_int) { drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_report_packet))); memset(dpkt, 0, sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_report_packet))); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_REPORT); dpkt->data_len = kis_hton32(sizeof(drone_report_packet)); drone_report_packet *rpkt = (drone_report_packet *) dpkt->data; rpkt->report_hdr_len = kis_hton16(sizeof(drone_report_packet)); rpkt->report_content_bitmap = kis_hton32(DRONEBIT(DRONE_REPORT_UUID) | DRONEBIT(DRONE_REPORT_FLAGS) | DRONEBIT(DRONE_REPORT_HOP_TM_SEC) | DRONEBIT(DRONE_REPORT_HOP_TM_USEC)); DRONE_CONV_UUID(in_int->strong_source->FetchUUID(), &(rpkt->uuid)); rpkt->flags = DRONE_REPORT_FLAG_NONE; if (in_int->error) rpkt->flags |= DRONE_REPORT_FLAG_ERROR; rpkt->hop_tm_sec = kis_hton32(in_int->tm_hop_time.tv_sec); rpkt->hop_tm_usec = kis_hton32(in_int->tm_hop_time.tv_usec); int ret = 0; ret = SendPacket(in_cl, dpkt); free(dpkt); return ret; } int KisDroneFramework::SendAllSourceReport(pst_packetsource *in_int) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendSourceReport(clvec[x], in_int) > 0) nsent++; } return nsent; } int KisDroneFramework::SendChannels(int in_cl, pst_packetsource *in_int) { if (in_int->strong_source == NULL) return 0; pst_channellist *channels = globalreg->sourcetracker->FetchSourceChannelList(in_int); drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_channelset_packet))); memset(dpkt, 0, sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_channelset_packet))); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_CHANNELSET); dpkt->data_len = kis_hton32(sizeof(drone_channelset_packet)); drone_channelset_packet *cpkt = (drone_channelset_packet *) dpkt->data; cpkt->channelset_hdr_len = kis_hton16(sizeof(drone_channelset_packet)); cpkt->channelset_content_bitmap = kis_hton32(DRONEBIT(DRONE_CHANNELSET_UUID) | DRONEBIT(DRONE_CHANNELSET_CMD) | DRONEBIT(DRONE_CHANNELSET_CURCH) | DRONEBIT(DRONE_CHANNELSET_HOP) | DRONEBIT(DRONE_CHANNELSET_NUMCH) | DRONEBIT(DRONE_CHANNELSET_CHANNELS) | DRONEBIT(DRONE_CHANNELSET_CHANNELSDWELL) | DRONEBIT(DRONE_CHANNELSET_HOPRATE) | DRONEBIT(DRONE_CHANNELSET_HOPDWELL)); DRONE_CONV_UUID(in_int->strong_source->FetchUUID(), &(cpkt->uuid)); cpkt->command = kis_ntoh16(DRONE_CHS_CMD_NONE); cpkt->cur_channel = kis_hton16(in_int->strong_source->FetchChannel()); cpkt->channel_hop = kis_hton16(in_int->channel_hop); cpkt->num_channels = kis_hton16(channels->channel_vec.size()); for (unsigned int x = 0; x < kismin(channels->channel_vec.size(), IPC_SOURCE_MAX_CHANS); x++) { if (channels->channel_vec[x].range == 0) { cpkt->chandata[x].u.chan_t.channel = kis_hton16(channels->channel_vec[x].u.chan_t.channel); cpkt->chandata[x].u.chan_t.dwell = kis_hton16(channels->channel_vec[x].u.chan_t.channel); } else { cpkt->chandata[x].u.range_t.start = kis_hton16(channels->channel_vec[x].u.range_t.start | (1 << 15)); cpkt->chandata[x].u.range_t.end = kis_hton16(channels->channel_vec[x].u.range_t.end); cpkt->chandata[x].u.range_t.width = kis_hton16(channels->channel_vec[x].u.range_t.width); cpkt->chandata[x].u.range_t.iter = kis_hton16(channels->channel_vec[x].u.range_t.iter); } /* cpkt->channels[x] = kis_hton16(channels->channel_vec[x].channel); cpkt->channels_dwell[x] = kis_hton16(channels->channel_vec[x].dwell); */ } cpkt->channel_rate = kis_hton16(in_int->channel_rate); cpkt->channel_dwell = kis_hton16(in_int->channel_dwell); int ret = 0; ret = SendPacket(in_cl, dpkt); free(dpkt); return ret; } int KisDroneFramework::SendAllChannels(pst_packetsource *in_int) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendChannels(clvec[x], in_int) > 0) nsent++; } return nsent; } int KisDroneFramework::SendPacket(int in_cl, drone_packet *in_pack) { int nlen = kis_ntoh32(in_pack->data_len) + sizeof(drone_packet); int ret = 0; ret = netserver->WriteData(in_cl, in_pack, nlen); if (ret == -2) { ostringstream osstr; osstr << "Kismet drone server client fd " << in_cl << " ring buffer " "full, throwing away packet"; _MSG(osstr.str(), (MSGFLAG_INFO | MSGFLAG_LOCAL)); return 0; } return ret; } int KisDroneFramework::SendAllPacket(drone_packet *in_pack) { vector clvec; int nsent = 0; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); for (unsigned int x = 0; x < clvec.size(); x++) { if (SendPacket(clvec[x], in_pack) > 0) nsent++; } return nsent; } // Send a new source to all the clients void KisDroneFramework::sourceact_handler(pst_packetsource *src, int action, int flags) { if (action == SOURCEACT_ADDSOURCE) { // Push a new source SendAllSource(src, 0); } else if (action == SOURCEACT_DELSOURCE) { // Push a remove action SendAllSource(src, 1); } else if (action == SOURCEACT_HOPENABLE || action == SOURCEACT_HOPDISABLE || action == SOURCEACT_CHVECTOR) { // Push a full channel info frame if we change hopping or channel vector SendAllChannels(src); } } // Grab a frame off the chain and format it as best we can to send to the // drone client. We automatically handle sending or not sending GPS data // based on its presence in the chain packet. Same with signal level data. int KisDroneFramework::chain_handler(kis_packet *in_pack) { vector clvec; if (netserver == NULL) return 0; netserver->FetchClientVector(&clvec); if (clvec.size() <= 0) return 0; kis_gps_packinfo *gpsinfo = NULL; kis_layer1_packinfo *radio = NULL; kis_datachunk *chunk = NULL; kis_ref_capsource *csrc_ref = NULL; kis_fcs_bytes *fcs = NULL; // Get the capsource info csrc_ref = (kis_ref_capsource *) in_pack->fetch(_PCM(PACK_COMP_KISCAPSRC)); // Get gps info gpsinfo = (kis_gps_packinfo *) in_pack->fetch(_PCM(PACK_COMP_GPS)); // Get radio-header info radio = (kis_layer1_packinfo *) in_pack->fetch(_PCM(PACK_COMP_RADIODATA)); // Get any fcs data fcs = (kis_fcs_bytes *) in_pack->fetch(_PCM(PACK_COMP_FCSBYTES)); // Try to find if we have a data chunk through various means chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_MANGLEFRAME)); if (chunk == NULL) { chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_80211FRAME)); } if (chunk == NULL) { chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME)); } if (fcs == NULL) { fcs = new kis_fcs_bytes; fcs->fcs[0] = 0xDE; fcs->fcs[1] = 0xAD; fcs->fcs[2] = 0xBE; fcs->fcs[3] = 0xEF; } // Add up the size of the packet for the data[0] component uint32_t packet_len = sizeof(drone_capture_packet); if (gpsinfo != NULL && gpsinfo->gps_fix >= 2) packet_len += sizeof(drone_capture_sub_gps); if (radio != NULL) packet_len += sizeof(drone_capture_sub_radio); if (fcs != NULL) packet_len += 4; if (chunk != NULL) { packet_len += sizeof(drone_capture_sub_data); packet_len += chunk->length; } // Packet = size of a normal packet + dynamic packetlen drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + packet_len)); // Zero it memset(dpkt, 0, sizeof(uint8_t) * (sizeof(drone_packet) + packet_len)); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_CAPPACKET); dpkt->data_len = kis_hton32(packet_len); // Capture frame starts at the drone_packet data field drone_capture_packet *dcpkt = (drone_capture_packet *) dpkt->data; unsigned int suboffst = 0; // Fill in the bitmap if (radio != NULL) { dcpkt->cap_content_bitmap |= DRONEBIT(DRONE_CONTENT_RADIO); drone_capture_sub_radio *rcpkt = (drone_capture_sub_radio *) &(dcpkt->content[suboffst]); suboffst += sizeof(drone_capture_sub_radio); rcpkt->radio_hdr_len = kis_hton16(sizeof(drone_capture_sub_radio)); // We have all the frields. This could be reduced to an integer // assign but that would suck to edit in the future, and this all // optomizes away into a single assign anyhow during compile rcpkt->radio_content_bitmap = kis_hton32(DRONEBIT(DRONE_RADIO_ACCURACY) | DRONEBIT(DRONE_RADIO_FREQ_MHZ) | DRONEBIT(DRONE_RADIO_SIGNAL_DBM) | DRONEBIT(DRONE_RADIO_NOISE_DBM) | DRONEBIT(DRONE_RADIO_CARRIER) | DRONEBIT(DRONE_RADIO_ENCODING) | DRONEBIT(DRONE_RADIO_DATARATE) | DRONEBIT(DRONE_RADIO_SIGNAL_RSSI) | DRONEBIT(DRONE_RADIO_NOISE_RSSI)); rcpkt->radio_accuracy = kis_hton16(radio->accuracy); rcpkt->radio_freq_mhz = kis_hton16(radio->freq_mhz); rcpkt->radio_signal_dbm = kis_hton16((int16_t) radio->signal_dbm); rcpkt->radio_noise_dbm = kis_hton16((int16_t) radio->noise_dbm); rcpkt->radio_carrier = kis_hton32((uint32_t) radio->carrier); rcpkt->radio_encoding = kis_hton32((uint32_t) radio->encoding); rcpkt->radio_datarate = kis_hton32(radio->datarate); rcpkt->radio_signal_rssi = kis_hton16((int16_t) radio->signal_rssi); rcpkt->radio_noise_rssi = kis_hton16((int16_t) radio->noise_rssi); } if (gpsinfo != NULL && gpsinfo->gps_fix >= 2) { dcpkt->cap_content_bitmap |= DRONEBIT(DRONE_CONTENT_GPS); drone_capture_sub_gps *gppkt = (drone_capture_sub_gps *) &(dcpkt->content[suboffst]); suboffst += sizeof(drone_capture_sub_gps); gppkt->gps_hdr_len = kis_hton16(sizeof(drone_capture_sub_gps)); gppkt->gps_content_bitmap = kis_hton32(DRONEBIT(DRONE_GPS_FIX) | DRONEBIT(DRONE_GPS_LAT) | DRONEBIT(DRONE_GPS_LON) | DRONEBIT(DRONE_GPS_ALT) | DRONEBIT(DRONE_GPS_SPD) | DRONEBIT(DRONE_GPS_HEADING)); gppkt->gps_fix = kis_hton16(gpsinfo->gps_fix); DRONE_CONV_DOUBLE(gpsinfo->lat, &(gppkt->gps_lat)); DRONE_CONV_DOUBLE(gpsinfo->lon, &(gppkt->gps_lon)); DRONE_CONV_DOUBLE(gpsinfo->alt, &(gppkt->gps_alt)); DRONE_CONV_DOUBLE(gpsinfo->spd, &(gppkt->gps_spd)); DRONE_CONV_DOUBLE(gpsinfo->heading, &(gppkt->gps_heading)); } if (fcs != NULL) { dcpkt->cap_content_bitmap |= DRONEBIT(DRONE_CONTENT_FCS); memcpy(&(dcpkt->content[suboffst]), fcs->fcs, 4); suboffst += 4; } // Other packet types go here // Finally the eight11 headers and the packet chunk itself if (chunk != NULL && in_pack->error == 0 && csrc_ref != NULL) { dcpkt->cap_content_bitmap |= DRONEBIT(DRONE_CONTENT_IEEEPACKET); drone_capture_sub_data *e1pkt = (drone_capture_sub_data *) &(dcpkt->content[suboffst]); // Set the offset to be the head of the eight11 frame since we // skip to the end of the content set dcpkt->cap_packet_offset = kis_hton32(suboffst); suboffst += sizeof(drone_capture_sub_data); e1pkt->data_hdr_len = kis_hton16(sizeof(drone_capture_sub_data)); e1pkt->data_content_bitmap = kis_hton32(DRONEBIT(DRONE_DATA_PACKLEN) | DRONEBIT(DRONE_DATA_UUID) | DRONEBIT(DRONE_DATA_TVSEC) | DRONEBIT(DRONE_DATA_TVUSEC) | DRONEBIT(DRONE_DATA_DLT)); DRONE_CONV_UUID(csrc_ref->ref_source->FetchUUID(), &(e1pkt->uuid)); e1pkt->packet_len = kis_hton16(chunk->length); e1pkt->tv_sec = kis_hton64(in_pack->ts.tv_sec); e1pkt->tv_usec = kis_hton64(in_pack->ts.tv_usec); e1pkt->dlt = kis_hton32(chunk->dlt); memcpy(e1pkt->packdata, chunk->data, chunk->length); } dcpkt->cap_content_bitmap = kis_hton32(dcpkt->cap_content_bitmap); SendAllPacket(dpkt); free(dpkt); return 1; } int KisDroneFramework::time_handler() { // Send everyone a NULL frame as a keepalove drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * sizeof(drone_packet)); memset(dpkt, 0, sizeof(uint8_t) * sizeof(drone_packet)); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_NULL); dpkt->data_len = kis_hton32(0); SendAllPacket(dpkt); return 1; } int KisDroneFramework::channel_handler(const drone_packet *in_pack) { ostringstream osstr; uint32_t len = kis_ntoh32(in_pack->data_len); if (len < sizeof(drone_channelset_packet)) return -1; drone_channelset_packet *csp = (drone_channelset_packet *) in_pack->data; uint32_t cbm = kis_ntoh32(csp->channelset_content_bitmap); // We can't handle it if it doesn't have at least this much set if ((cbm & DRONEBIT(DRONE_CHANNELSET_UUID)) == 0 || (cbm & DRONEBIT(DRONE_CHANNELSET_CMD)) == 0) { return 0; } uuid intuuid; UUID_CONV_DRONE(&(csp->uuid), intuuid); int cmd; cmd = kis_ntoh16(csp->command); if (cmd == DRONE_CHS_CMD_SETVEC && (cbm & DRONEBIT(DRONE_CHANNELSET_NUMCH)) && (cbm & DRONEBIT(DRONE_CHANNELSET_CHANNELS)) && (cbm & DRONEBIT(DRONE_CHANNELSET_CHANNELSDWELL))) { ostringstream chstr; uint16_t nch = kis_ntoh16(csp->num_channels); // Make a new channel list based on the UUID chstr << intuuid.UUID2String() << ":"; for (unsigned int x = 0; x < nch; x++) { /* uint16_t ch = kis_ntoh16(csp->channels[x]); uint16_t dw = kis_ntoh16(csp->channels_dwell[x]); chstr << ch << ":" << dw << ","; */ if (kis_ntoh16(csp->chandata[x].u.chan_t.channel) >> 15) { chstr << "range-" << (kis_ntoh16(csp->chandata[x].u.range_t.start) & ~(1 << 15)) << "-" << kis_ntoh16(csp->chandata[x].u.range_t.end) << "-" << kis_ntoh16(csp->chandata[x].u.range_t.width) << "-" << kis_ntoh16(csp->chandata[x].u.range_t.iter); } else { chstr << kis_ntoh16(csp->chandata[x].u.chan_t.channel) << ":" << kis_ntoh16(csp->chandata[x].u.chan_t.dwell); } if (x != (unsigned int) nch - 1) chstr << ","; } _MSG("Setting source " + intuuid.UUID2String() + " channel vector to " + chstr.str(), MSGFLAG_INFO); return globalreg->sourcetracker->SetSourceNewChannellist(intuuid, chstr.str()); } if ((cmd == DRONE_CHS_CMD_SETHOP || cmd == DRONE_CHS_CMD_SETCUR) && (cbm & DRONEBIT(DRONE_CHANNELSET_HOP)) && (cbm & DRONEBIT(DRONE_CHANNELSET_CURCH))) { int hopping = kis_ntoh16(csp->channel_hop); uint16_t curch = kis_ntoh16(csp->cur_channel); osstr << (hopping ? string("Enabling") : string("Disabling")) << " "; osstr << "channel hopping on " << intuuid.UUID2String(); if (hopping) osstr << " and locking to channel " << curch; _MSG(osstr.str(), MSGFLAG_INFO); return globalreg->sourcetracker->SetSourceHopping(intuuid, hopping, curch); } if (cmd == DRONE_CHS_CMD_SETHOPDWELL && (cbm & DRONEBIT(DRONE_CHANNELSET_HOPRATE)) && (cbm & DRONEBIT(DRONE_CHANNELSET_HOPDWELL))) { uint16_t hoprate = kis_ntoh16(csp->channel_rate); uint16_t hopdwell = kis_ntoh16(csp->channel_dwell); if (hoprate != 0) osstr << "Setting hop rate to " << hoprate << " channels per second on " "source " << intuuid.UUID2String(); else osstr << "Setting channel dwell to " << hopdwell << " seconds per " "channel on source " << intuuid.UUID2String(); _MSG(osstr.str(), MSGFLAG_INFO); return globalreg->sourcetracker->SetSourceHopDwell(intuuid, hoprate, hopdwell); } return 0; } kismet-2013-03-R1b/conf/0000775000175000017500000000000012124602454014400 5ustar dragorndragornkismet-2013-03-R1b/conf/kismet.conf.in0000664000175000017500000002706212124602454017157 0ustar dragorndragorn# Kismet config file # Most of the "static" configs have been moved to here -- the command line # config was getting way too crowded and cryptic. We want functionality, # not continually reading --help! # Version of Kismet config version=2009-newcore # Name of server (Purely for organizational purposes) # If commented out, defaults to host name of system # servername=Kismet Server # Prefix of where we log (as used in the logtemplate later) # logprefix=/some/path/to/logs # Do we process the contents of data frames? If this is enabled, data # frames will be truncated to the headers only immediately after frame type # detection. This will disable IP detection, etc, however it is likely # safer (and definitely more polite) if monitoring networks you do not own. # hidedata=true # Do we allow plugins to be used? This will load plugins from the system # and user plugin directiories when set to true (See the README for the default # plugin locations). allowplugins=true # See the README for full information on the new source format # ncsource=interface:options # for example: # ncsource=wlan0 # ncsource=wifi0:type=madwifi # ncsource=wlan0:name=intel,hop=false,channel=11 # Comma-separated list of sources to enable. This is only needed if you defined # multiple sources and only want to enable some of them. By default, all defined # sources are enabled. # For example, if sources with name=prismsource and name=ciscosource are defined, # and you only want to enable those two: # enablesources=prismsource,ciscosource # Control which channels we like to spend more time on. By default, the list # of channels is pulled from the driver automatically. By setting preferred channels, # if they are present in the channel list, they'll be set with a timing delay so that # more time is spent on them. Since 1, 6, 11 are the common default channels, it makes # sense to spend more time monitoring them. # For finer control, see further down in the config for the channellist= directives. preferredchannels=1,6,11 # How many channels per second do we hop? (1-10) channelvelocity=3 # By setting the dwell time for channel hopping we override the channelvelocity # setting above and dwell on each channel for the given number of seconds. #channeldwell=10 # Channels are defined as: # channellist=name:ch1,ch2,ch3 # or # channellist=name:range-start-end-width-offset,ch,range,ch,... # # Channels may be a numeric channel or a frequency # # Channels may specify an additional wait period. For common default channels, # an additional wait period can be useful. Wait periods delay for that number # of times per second - so a configuration hopping 10 times per second with a # channel of 6:3 would delay 3/10ths of a second on channel 6. # # Channel lists may have up to 256 channels and ranges (combined). For power # users scanning more than 256 channels with a single card, ranges must be used. # # Ranges are meant for "power users" who wish to define a very large number of # channels. A range may specify channels or frequencies, and will automatically # sort themselves to cover channels in a non-overlapping fashion. An example # range for the normal 802.11b/g spectrum would be: # # range-1-11-3-1 # # which indicates starting at 1, ending at 11, a channel width of 3 channels, # incrementing by one. A frequency based definition would be: # # range-2412-2462-22-5 # # since 11g channels are 22 mhz wide and 5 mhz apart. # # Ranges have the flaw that they cannot be shared between sources in a non-overlapping # way, so multiple sources using the same range may hop in lockstep with each other # and duplicate the coverage. # # channellist=demo:1:3,6:3,11:3,range-5000-6000-20-10 # Default channel lists # These channel lists MUST BE PRESENT for Kismet to work properly. While it is # possible to change these, it is not recommended. These are used when the supported # channel list can not be found for the source; to force using these instead of # the detected supported channels, override with channellist= in the source defintion # # IN GENERAL, if you think you want to modify these, what you REALLY want to do is # copy them and use channellist= in the packet source. channellist=IEEE80211b:1:3,6:3,11:3,2,7,3,8,4,9,5,10 channellist=IEEE80211a:36,40,44,48,52,56,60,64,149,153,157,161,165 channellist=IEEE80211ab:1:3,6:3,11:3,2,7,3,8,4,9,5,10,36,40,44,48,52,56,60,64,149,153,157,161,165 # Client/server listen config listen=tcp://127.0.0.1:2501 # People allowed to connect, comma seperated IP addresses or network/mask # blocks. Netmasks can be expressed as dotted quad (/255.255.255.0) or as # numbers (/24) allowedhosts=127.0.0.1 # Maximum number of concurrent GUI's maxclients=5 # Maximum backlog before we start throwing out or killing clients. The # bigger this number, the more memory and the more power it will use. maxbacklog=5000 # Server + Drone config options. To have a Kismet server export live packets # as if it were a drone, uncomment these. # dronelisten=tcp://127.0.0.1:3501 # droneallowedhosts=127.0.0.1 # dronemaxclients=5 # droneringlen=65535 # OUI file, expected format 00:11:22manufname # IEEE OUI file used to look up manufacturer info. We default to the # wireshark one since most people have that. ouifile=/etc/manuf ouifile=/usr/share/wireshark/wireshark/manuf ouifile=/usr/share/wireshark/manuf ouifile=/Applications/Wireshark.app/Contents/Resources/share/wireshark/manuf # Do we have a GPS? gps=true # Do we use a locally serial attached GPS, or use a gpsd server, or # use a fixed virtual gps? # (Pick only one) gpstype=gpsd # Host:port that GPSD is running on. This can be localhost OR remote! gpshost=localhost:2947 # gpstype=serial # What serial device do we look for the GPS on? # gpsdevice=/dev/rfcomm0 # gpstype=virtual # gpsposition=100,-50 # gpsaltitude=1234 # Do we lock the mode? This overrides coordinates of lock "0", which will # generate some bad information until you get a GPS lock, but it will # fix problems with GPS units with broken NMEA that report lock 0 gpsmodelock=false # Do we try to reconnect if we lose our link to the GPS, or do we just # let it die and be disabled? gpsreconnect=true # Do we export packets over tun/tap virtual interfaces? tuntap_export=false # What virtual interface do we use tuntap_device=kistap0 # Packet filtering options: # filter_tracker - Packets filtered from the tracker are not processed or # recorded in any way. # filter_export - Controls what packets influence the exported CSV, network, # xml, gps, etc files. # All filtering options take arguments containing the type of address and # addresses to be filtered. Valid address types are 'ANY', 'BSSID', # 'SOURCE', and 'DEST'. Filtering can be inverted by the use of '!' before # the address. For example, # filter_tracker=ANY(!"00:00:DE:AD:BE:EF") # has the same effect as the previous mac_filter config file option. # filter_tracker=... # filter_dump=... # filter_export=... # filter_netclient=... # Alerts to be reported and the throttling rates. # alert=name,throttle/unit,burst # The throttle/unit describes the number of alerts of this type that are # sent per time unit. Valid time units are second, minute, hour, and day. # Burst describes the number of alerts sent before throttling takes place. # For example: # alert=FOO,10/min,5 # Would allow 5 alerts through before throttling is enabled, and will then # limit the number of alerts to 10 per minute. # A throttle rate of 0 disables throttling of the alert. # See the README for a list of alert types. alert=ADHOCCONFLICT,5/min,1/sec alert=AIRJACKSSID,5/min,1/sec alert=APSPOOF,10/min,1/sec alert=BCASTDISCON,5/min,2/sec alert=BSSTIMESTAMP,5/min,1/sec alert=CHANCHANGE,5/min,1/sec alert=CRYPTODROP,5/min,1/sec alert=DISASSOCTRAFFIC,10/min,1/sec alert=DEAUTHFLOOD,5/min,2/sec alert=DEAUTHCODEINVALID,5/min,1/sec alert=DISCONCODEINVALID,5/min,1/sec alert=DHCPNAMECHANGE,5/min,1/sec alert=DHCPOSCHANGE,5/min,1/sec alert=DHCPCLIENTID,5/min,1/sec alert=DHCPCONFLICT,10/min,1/sec alert=NETSTUMBLER,5/min,1/sec alert=LUCENTTEST,5/min,1/sec alert=LONGSSID,5/min,1/sec alert=MSFBCOMSSID,5/min,1/sec alert=MSFDLINKRATE,5/min,1/sec alert=MSFNETGEARBEACON,5/min,1/sec alert=NULLPROBERESP,5/min,1/sec #alert=PROBENOJOIN,5/min,1/sec # Controls behavior of the APSPOOF alert. SSID may be a literal match (ssid=) or # a regex (ssidregex=) if PCRE was available when kismet was built. The allowed # MAC list must be comma-separated and enclosed in quotes if there are multiple # MAC addresses allowed. MAC address masks are allowed. apspoof=Foo1:ssidregex="(?i:foobar)",validmacs=00:11:22:33:44:55 apspoof=Foo2:ssid="Foobar",validmacs="00:11:22:33:44:55,aa:bb:cc:dd:ee:ff" # Known WEP keys to decrypt, bssid,hexkey. This is only for networks where # the keys are already known, and it may impact throughput on slower hardware. # Multiple wepkey lines may be used for multiple BSSIDs. # wepkey=00:DE:AD:C0:DE:00,FEEDFACEDEADBEEF01020304050607080900 # Is transmission of the keys to the client allowed? This may be a security # risk for some. If you disable this, you will not be able to query keys from # a client. allowkeytransmit=true # How often (in seconds) do we write all our data files (0 to disable) writeinterval=300 # Do we use sound? # Not to be confused with GUI sound parameter, this controls wether or not the # server itself will play sound. Primarily for headless or automated systems. enablesound=false # Path to sound player soundbin=play sound=newnet,true sound=newcryptnet,true sound=packet,true sound=gpslock,true sound=gpslost,true sound=alert,true # Does the server have speech? (Again, not to be confused with the GUI's speech) enablespeech=false # Binary used for speech (if not in path, full path must be specified) speechbin=flite # Specify raw or festival; Flite (and anything else that doesn't need formatting # around the string to speak) is 'raw', festival requires the string be wrapped in # SayText("...") speechtype=raw # How do we speak? Valid options: # speech Normal speech # nato NATO spellings (alpha, bravo, charlie) # spell Spell the letters out (aye, bee, sea) speechencoding=nato speech=new,"New network detected s.s.i.d. %1 channel %2" speech=alert,"Alert %1" speech=gpslost,"G.P.S. signal lost" speech=gpslock,"G.P.S. signal O.K." # How many alerts do we backlog for new clients? Only change this if you have # a -very- low memory system and need those extra bytes, or if you have a high # memory system and a huge number of alert conditions. alertbacklog=50 # File types to log, comma seperated. Built-in log file types: # alert Text file of alerts # gpsxml XML per-packet GPS log # nettxt Networks in text format # netxml Networks in XML format # pcapdump tcpdump/wireshark compatible pcap log file # string All strings seen (increases CPU load) logtypes=pcapdump,gpsxml,netxml,nettxt,alert # Format of the pcap dump (PPI or 80211) pcapdumpformat=ppi # pcapdumpformat=80211 # Default log title logdefault=Kismet # logtemplate - Filename logging template. # This is, at first glance, really nasty and ugly, but you'll hardly ever # have to touch it so don't complain too much. # # %p is replaced by the logging prefix + '/' # %n is replaced by the logging instance name # %d is replaced by the starting date as Mon-DD-YYYY # %D is replaced by the current date as YYYYMMDD # %t is replaced by the starting time as HH-MM-SS # %i is replaced by the increment log in the case of multiple logs # %l is replaced by the log type (pcapdump, strings, etc) # %h is replaced by the home directory logtemplate=%p%n-%D-%t-%i.%l # Where state info, etc, is stored. You shouldnt ever need to change this. # This is a directory. configdir=%h/.kismet/ kismet-2013-03-R1b/conf/kismet_drone.conf0000664000175000017500000000414212124602454017733 0ustar dragorndragorn# Kismet drone config file version=newcore.1 # Name of drone server (informational) servername=Kismet-Drone # Drone configuration # Protocol, interface, and port to listen on dronelisten=tcp://127.0.0.1:2502 # Hosts allowed to connect, comma separated. May include netmasks. # allowedhosts=127.0.0.1,10.10.10.0/255.255.255.0 droneallowedhosts=127.0.0.1 # Maximum number of drone clients dronemaxclients=10 droneringlen=65535 # Do we have a GPS? gps=true # Do we use a locally serial attached GPS, or use a gpsd server? # (Pick only one) gpstype=gpsd # gpstype=serial # What serial device do we look for the GPS on? gpsdevice=/dev/rfcomm0 # Host:port that GPSD is running on. This can be localhost OR remote! gpshost=localhost:2947 # Do we lock the mode? This overrides coordinates of lock "0", which will # generate some bad information until you get a GPS lock, but it will # fix problems with GPS units with broken NMEA that report lock 0 gpsmodelock=false # Do we try to reconnect if we lose our link to the GPS, or do we just # let it die and be disabled? gpsreconnect=true # See the README for full information on the new source format # ncsource=interface:options ncsource=null # for example: # ncsource=wlan0 # ncsource=wifi0:type=madwifi # ncsource=wlan0:name=intel,hop=false,channel=11 # Special per-source options # sourceopts=[sourcename|*]:opt1,opt2 # sourceopts=*:fuzzycrypt,weakvalidate # Comma-separated list of sources to enable, if you don't want to enable all # the sources you defined. # enablesource=source1,source2 # How many channels per second do we hop? (1-10) channelvelocity=5 # By setting the dwell time for channel hopping we override the channelvelocity # setting above and dwell on each channel for the given number of seconds. #channeldwell=10 # Users outside the US might want to use this list: # channellist=IEEE80211b:1,7,13,2,8,3,14,9,4,10,5,11,6,12 channellist=IEEE80211b:1:3,6:3,11:3,2,7,3,8,4,9,5,10 # US IEEE 80211a channellist=IEEE80211a:36,40,44,48,52,56,60,64,149,153,157,161,165 # Combo channellist=IEEE80211ab:1:3,6:3,11:3,2,7,3,8,4,9,5,10,36,40,44,48,52,56,60,64,149,153,157,161,165 kismet-2013-03-R1b/psutils.h0000664000175000017500000000175012124602454015332 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PSUTILS_H__ #define __PSUTILS_H__ #include "config.h" #include // Find a process including the name in_proc and the commandline option // in_option, both are partial matches int FindProcess(string in_proc, string in_option); #endif kismet-2013-03-R1b/gpswrapper.h0000664000175000017500000000362712124602454016026 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "gpscore.h" #include "gpsserial.h" #include "gpsdclient.h" #ifndef __GPSWRAPPER_H__ #define __GPSWRAPPER_H__ // Simple wrapper class to parse the gps line and spawn the proper gps module class GpsWrapper { public: GpsWrapper() { fprintf(stderr, "FATAL OOPS: GpsWrapper()\n"); exit(1); } static void Usage(char *argv); GpsWrapper(GlobalRegistry *globalreg); GPSCore *gps; }; // Empty GPS handler which inserts the network protocols but doesn't do anything // else, so that clients don't get unhappy class GPSNull : public GPSCore { public: GPSNull() { fprintf(stderr, "FATAL OOPS: GPSNull()\n"); exit(1); } GPSNull(GlobalRegistry *in_globalreg) : GPSCore(in_globalreg) { // We don't parse our options RegisterComponents(); } virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return in_max_fd; } virtual int Poll(fd_set &in_rset, fd_set& in_wset) { return 0; } virtual int ParseData() { return 0; } virtual int KillConnection() { return 0; } virtual int Shutdown() { return 0; } virtual int InjectCommand() { return 1; } virtual int Reconnect() { return 0; } protected: }; #endif kismet-2013-03-R1b/.gitignore0000664000175000017500000000037612124602454015451 0ustar dragorndragorn*.o # vim session .*.swp # generated by configure .depend Makefile Makefile.inc config.* conf/kismet.conf scripts/kismet aclocal.m4 autom4te.cache/ # built binaries kismet_capture kismet_client kismet_drone kismet_server # Plugin stuff plugin-*/*.so kismet-2013-03-R1b/phy_80211.cc0000664000175000017500000000307112124602454015316 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "packetchain.h" #include "kis_netframe.h" #include "timetracker.h" #include "filtercore.h" #include "gpscore.h" #include "packet.h" #include "uuid.h" #include "configfile.h" #include "devicetracker.h" #include "phy_80211.h" Kis_80211_Phy::Kis_80211_Phy(GlobalRegistry *in_globalreg, Devicetracker *in_tracker, int in_phyid) : Kis_Phy_Handler(in_globalreg, in_tracker, in_phyid) { // todo _MSG("Registered 80211 PHY as id " + IntToString(in_phyid), MSGFLAG_INFO); } int Kis_80211_Phy::HandlePacket(kis_packet *in_pack) { return 1; } int Kis_80211_Phy::TimerKick() { return 1; } kismet-2013-03-R1b/manuf.cc0000664000175000017500000001022212124602454015065 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "configfile.h" #include "messagebus.h" #include "util.h" #include "manuf.h" Manuf::Manuf(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Manuf called before kismet_config\n"); exit(1); } vector fname = globalreg->kismet_config->FetchOptVec("ouifile"); if (fname.size() == 0) { _MSG("Missing 'ouifile' option in config, will not resolve manufacturer " "names for MAC addresses", MSGFLAG_ERROR); return; } for (unsigned int x = 0; x < fname.size(); x++) { if ((mfile = fopen(fname[x].c_str(), "r")) != NULL) { _MSG("Opened OUI file '" + fname[x], MSGFLAG_INFO); break; } _MSG("Could not open OUI file '" + fname[x] + "': " + string(strerror(errno)), MSGFLAG_ERROR); } if (mfile == NULL) { _MSG("No OUI files were available, will not resolve manufacturer " "names for MAC addresses", MSGFLAG_ERROR); return; } IndexOUI(); } void Manuf::IndexOUI() { char buf[1024]; int line = 0; fpos_t prev_pos; short int m[3]; if (mfile == NULL) return; _MSG("Indexing manufacturer db", MSGFLAG_INFO); fgetpos(mfile, &prev_pos); while (!feof(mfile)) { if (fgets(buf, 1024, mfile) == NULL || feof(mfile)) break; if ((line % 50) == 0) { if (sscanf(buf, "%hx:%hx:%hx", &(m[0]), &(m[1]), &(m[2])) == 3) { // Log a position at the previous pos - which is the line before // this one, so we're inclusive index_pos ip; uint32_t oui; oui = 0; oui |= (uint32_t) m[0] << 16; oui |= (uint32_t) m[1] << 8; oui |= (uint32_t) m[2]; ip.oui = oui; ip.pos = prev_pos; index_vec.push_back(ip); } else { // Compensate for not getting a reasonable line (probably a // comment) by decrementing here so we keep trying at each // index point until we get info we're looking for line--; } } fgetpos(mfile, &prev_pos); line++; } _MSG("Completed indexing manufacturer db, " + IntToString(line) + " lines " + IntToString(index_vec.size()) + " indexes", MSGFLAG_INFO); } string Manuf::LookupOUI(mac_addr in_mac) { uint32_t soui = in_mac.OUI(), toui; int matched = -1; char buf[1024]; short int m[3]; char manuf[16]; if (mfile == NULL) return "Unknown"; // Use the cache first if (oui_map.find(soui) != oui_map.end()) { return oui_map[soui].manuf; } for (unsigned int x = 0; x < index_vec.size(); x++) { if (soui > index_vec[x].oui) continue; matched = x - 1; break; } // Cache unknown to save us effort in the future if (matched < 0) { manuf_data md; md.oui = soui; md.manuf = "Unknown"; oui_map[soui] = md; return md.manuf; } fsetpos(mfile, &(index_vec[matched].pos)); while (!feof(mfile)) { if (fgets(buf, 1024, mfile) == NULL || feof(mfile)) break; if (sscanf(buf, "%hx:%hx:%hx\t%10s", &(m[0]), &(m[1]), &(m[2]), manuf) == 4) { // Log a position at the previous pos - which is the line before // this one, so we're inclusive toui = 0; toui |= (uint32_t) m[0] << 16; toui |= (uint32_t) m[1] << 8; toui |= (uint32_t) m[2]; if (toui == soui) { manuf_data md; md.oui = soui; md.manuf = MungeToPrintable(string(manuf)); oui_map[soui] = md; return md.manuf; } if (toui > soui) { manuf_data md; md.oui = soui; md.manuf = "Unknown"; oui_map[soui] = md; return md.manuf; } } } return "Unknown"; } kismet-2013-03-R1b/kis_panel_details.cc0000664000175000017500000020533012124602454017437 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include #include #include #include #include #include #include #include #include "kis_panel_widgets.h" #include "kis_panel_frontend.h" #include "kis_panel_windows.h" #include "kis_panel_preferences.h" #include "kis_panel_details.h" int NetDetailsButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_NetDetails_Panel *) aux)->ButtonAction(component); return 1; } int NetDetailsMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_NetDetails_Panel *) aux)->MenuAction(status); return 1; } int NetDetailsGraphEvent(TIMEEVENT_PARMS) { return ((Kis_NetDetails_Panel *) parm)->GraphTimer(); } Kis_NetDetails_Panel::Kis_NetDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { grapheventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &NetDetailsGraphEvent, (void *) this); menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, NetDetailsMenuCB, this); mn_network = menu->AddMenu("Network", 0); mi_addnote = menu->AddMenuItem("Network Note...", mn_network, 'N'); menu->AddMenuItem("-", mn_network, 0); mi_nextnet = menu->AddMenuItem("Next network", mn_network, 'n'); mi_prevnet = menu->AddMenuItem("Prev network", mn_network, 'p'); menu->AddMenuItem("-", mn_network, 0); mi_close = menu->AddMenuItem("Close window", mn_network, 'w'); mn_view = menu->AddMenu("View", 0); mi_net = menu->AddMenuItem("Network Details", mn_view, 'n'); mi_clients = menu->AddMenuItem("Clients", mn_view, 'c'); menu->AddMenuItem("-", mn_view, 0); mi_graphsig = menu->AddMenuItem("Signal Level", mn_view, 's'); mi_graphpacket = menu->AddMenuItem("Packet Rate", mn_view, 'p'); mi_graphretry = menu->AddMenuItem("Retry Rate", mn_view, 'r'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); netdetailt = new Kis_Free_Text(globalreg, this); AddComponentVec(netdetailt, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); #if 0 // Details scroll list doesn't get the current one highlighted and // doesn't draw titles, also lock to fit inside the window netdetails = new Kis_Scrollable_Table(globalreg, this); netdetails->SetHighlightSelected(0); netdetails->SetLockScrollTop(1); netdetails->SetDrawTitles(0); AddComponentVec(netdetails, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); // We need to populate the titles even if we don't use them so that // the row handler knows how to draw them vector titles; Kis_Scrollable_Table::title_data t; t.width = 15; t.title = "field"; t.alignment = 2; titles.push_back(t); t.width = 0; t.title = "value"; t.alignment = 0; titles.push_back(t); netdetails->AddTitles(titles); netdetails->Show(); #endif siggraph = new Kis_IntGraph(globalreg, this); siggraph->SetName("DETAIL_SIG"); siggraph->SetPreferredSize(0, 8); siggraph->SetScale(-110, -40); siggraph->SetInterpolation(1); siggraph->SetMode(0); siggraph->Show(); siggraph->AddExtDataVec("Signal", 4, "graph_detail_sig", "yellow,yellow", ' ', ' ', 1, &sigpoints); AddComponentVec(siggraph, KIS_PANEL_COMP_EVT); packetgraph = new Kis_IntGraph(globalreg, this); packetgraph->SetName("DETAIL_PPS"); packetgraph->SetPreferredSize(0, 8); packetgraph->SetScale(0, 0); packetgraph->SetInterpolation(1); packetgraph->SetMode(0); packetgraph->Show(); packetgraph->AddExtDataVec("Packet Rate", 4, "graph_detail_pps", "green,green", ' ', ' ', 1, &packetpps); AddComponentVec(packetgraph, KIS_PANEL_COMP_EVT); retrygraph = new Kis_IntGraph(globalreg, this); retrygraph->SetName("DETAIL_RETRY_PPS"); retrygraph->SetPreferredSize(0, 8); retrygraph->SetScale(0, 0); retrygraph->SetInterpolation(1); retrygraph->SetMode(0); retrygraph->Show(); retrygraph->AddExtDataVec("Retry Rate", 4, "graph_detail_retrypps", "red,red", ' ', ' ', 1, &retrypps); AddComponentVec(retrygraph, KIS_PANEL_COMP_EVT); ClearGraphVectors(); SetTitle(""); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(siggraph, 0, 0); vbox->Pack_End(packetgraph, 0, 0); vbox->Pack_End(retrygraph, 0, 0); vbox->Pack_End(netdetailt, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); last_dirty = 0; last_mac = mac_addr(0); dng = NULL; vector td; td.push_back(""); td.push_back("No network selected / Empty network selected"); td.push_back("Change sort order to anything other than \"Auto Fit\""); td.push_back("and highlight a network."); netdetailt->SetText(td); UpdateViewMenu(-1); SetActiveComponent(netdetailt); main_component = vbox; Position(WIN_CENTER(LINES, COLS)); } Kis_NetDetails_Panel::~Kis_NetDetails_Panel() { if (grapheventid >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(grapheventid); } void Kis_NetDetails_Panel::ClearGraphVectors() { lastpackets = 0; sigpoints.clear(); packetpps.clear(); retrypps.clear(); for (unsigned int x = 0; x < 120; x++) { sigpoints.push_back(-256); packetpps.push_back(0); retrypps.push_back(0); } } void Kis_NetDetails_Panel::UpdateGraphVectors(int signal, int pps, int retry) { sigpoints.push_back(signal); if (sigpoints.size() > 120) sigpoints.erase(sigpoints.begin(), sigpoints.begin() + sigpoints.size() - 120); if (lastpackets == 0) lastpackets = pps; packetpps.push_back(pps - lastpackets); lastpackets = pps; if (packetpps.size() > 120) packetpps.erase(packetpps.begin(), packetpps.begin() + packetpps.size() - 120); retrypps.push_back(retry); if (retrypps.size() > 120) retrypps.erase(retrypps.begin(), retrypps.begin() + retrypps.size() - 120); } string crypt_to_str(uint64_t cryptset) { ostringstream osstr; if (cryptset == 0) osstr << "None (Open)"; if (cryptset == crypt_wep) osstr << "WEP (Privacy bit set)"; if (cryptset & crypt_layer3) osstr << " Layer3"; if (cryptset & crypt_wpa_migmode) osstr << " WPA Migration Mode"; if (cryptset & crypt_wep40) osstr << " WEP (40bit)"; if (cryptset & crypt_wep104) osstr << " WEP (104bit)"; if (cryptset & crypt_wpa) osstr << " WPA"; if (cryptset & crypt_tkip) osstr << " TKIP"; if (cryptset & crypt_psk) osstr << " PSK"; if (cryptset & crypt_aes_ocb) osstr << " AES-ECB"; if (cryptset & crypt_aes_ccm) osstr << " AES-CCM"; if (cryptset & crypt_leap) osstr << " LEAP"; if (cryptset & crypt_ttls) osstr << " TTLS"; if (cryptset & crypt_tls) osstr << " TLS"; if (cryptset & crypt_peap) osstr << " PEAP"; if (cryptset & crypt_isakmp) osstr << " ISA-KMP"; if (cryptset & crypt_pptp) osstr << " PPTP"; if (cryptset & crypt_fortress) osstr << " Fortress"; if (cryptset & crypt_keyguard) osstr << " Keyguard"; if (cryptset & crypt_unknown_nonwep) osstr << " WPA/ExtIV data"; return osstr.str(); } int Kis_NetDetails_Panel::AppendSSIDInfo(vector *td, Netracker::tracked_network *net, Netracker::adv_ssid_data *ssid) { ostringstream osstr; if (ssid != NULL) { osstr.str(""); osstr << ssid->ssid; if (ssid->type == ssid_beacon) { if (ssid->ssid != "") osstr << " "; if (ssid->ssid_cloaked) osstr << "(Cloaked)"; } else if (ssid->type == ssid_probereq && ssid->ssid == "") { osstr << "(Broadcast request)"; } td->push_back(AlignString("SSID: ", ' ', 2, 16) + osstr.str()); // Look for probable matches if (ssid->ssid_cloaked && ssid->ssid == "" && ssid->type == ssid_beacon) { ssid_type t = ssid_file; for (map::iterator asi = net->ssid_map.begin(); asi != net->ssid_map.end(); ++asi) { if (asi->second->type == ssid_proberesp && t == ssid_file) { td->push_back(AlignString("Probable Decloak: ", ' ', 2, 18) + asi->second->ssid); break; } else if (asi->second->type == ssid_file) { td->push_back(AlignString("Cached: ", ' ', 2, 18) + asi->second->ssid); } } } td->push_back(AlignString("Length: ", ' ', 2, 18) + IntToString(ssid->ssid.length())); osstr.str(""); if (ssid->type == ssid_beacon) osstr << "Beacon (advertising AP)"; else if (ssid->type == ssid_probereq) osstr << "Request (searching client)"; else if (ssid->type == ssid_proberesp) osstr << "Response (responding AP)"; else if (ssid->type == ssid_file) osstr << "Previously cached SSID"; else osstr << "Unknown"; td->push_back(AlignString("Type: ", ' ', 2, 18) + osstr.str()); if (ssid->dot11d_vec.size() > 0) { td->push_back(AlignString("802.11d Country: ", ' ', 2, 18) + ssid->dot11d_country); for (unsigned int z = 0; z < ssid->dot11d_vec.size(); z++) { td->push_back(AlignString("", ' ', 2, 18) + string("Channel ") + IntToString(ssid->dot11d_vec[z].startchan) + string("-") + IntToString(ssid->dot11d_vec[z].startchan + ssid->dot11d_vec[z].numchan - 1) + string(" ") + IntToString(ssid->dot11d_vec[z].txpower) + string("dBm")); } } osstr.str(crypt_to_str(ssid->cryptset)); td->push_back(AlignString("Encryption: ", ' ', 2, 18) + osstr.str()); if (net->type == network_ap) { if (ssid->beacons > ssid->beaconrate) ssid->beacons = ssid->beaconrate; int brate = (int) (((double) ssid->beacons / (double) ssid->beaconrate) * 100); if (brate > 0) { td->push_back(AlignString("Beacon %: ", ' ', 2, 18) + IntToString(brate)); } } } return 1; } int Kis_NetDetails_Panel::AppendNetworkInfo(vector *td, Kis_Display_NetGroup *tng, Netracker::tracked_network *net) { vector *netvec = NULL; ostringstream osstr; if (tng != NULL) netvec = tng->FetchNetworkVec(); td->push_back(AlignString("Name: ", ' ', 2, 16) + tng->GetName(net)); if (net == NULL && netvec != NULL && netvec->size() > 1) { td->push_back(AlignString("# Networks: ", ' ', 2, 16) + IntToString(netvec->size())); } // Use the display metanet if we haven't been given one if (net == NULL && dng != NULL) net = dng->FetchNetwork(); // Catch nulls just incase if (net == NULL) return 0; td->push_back(AlignString("BSSID: ", ' ', 2, 16) + net->bssid.Mac2String()); td->push_back(AlignString("Manuf: ", ' ', 2, 16) + net->manuf); osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(net->first_time)) + 4).substr(0, 15)); td->push_back(AlignString("First Seen: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(net->last_time)) + 4).substr(0, 15)); td->push_back(AlignString("Last Seen: ", ' ', 2, 16) + osstr.str()); osstr.str(""); if (net->type == network_ap) osstr << "Access Point (Managed/Infrastructure)"; else if (net->type == network_probe) osstr << "Probe (Client)"; else if (net->type == network_turbocell) osstr << "Turbocell"; else if (net->type == network_data) osstr << "Data Only (No management)"; else if (net->type == network_mixed) osstr << "Mixed (Multiple network types in group)"; else osstr << "Unknown"; td->push_back(AlignString("Type: ", ' ', 2, 16) + osstr.str()); osstr.str(""); if (net->channel != 0) osstr << net->channel; else osstr << "No channel identifying information seen"; td->push_back(AlignString("Channel: ", ' ', 2, 16) + osstr.str()); for (map::const_iterator fmi = net->freq_mhz_map.begin(); fmi != net->freq_mhz_map.end(); ++fmi) { float perc = ((float) fmi->second / (float) (net->llc_packets + net->data_packets)) * 100; int ch = FreqToChan(fmi->first); ostringstream chtxt; if (ch != 0) chtxt << ch; else chtxt << "Unk"; osstr.str(""); osstr << fmi->first << " (" << chtxt.str() << ") - " << fmi->second << " packets, " << NtoString(perc, 2).Str() << "%"; td->push_back(AlignString(fmi == net->freq_mhz_map.begin() ? "Frequency: " : "", ' ', 2, 16) + osstr.str()); } if (netvec == NULL || (netvec != NULL && netvec->size() == 1)) { if (net->ssid_map.size() > 1) { if (net->lastssid != NULL) { if (net->lastssid->ssid != "") { td->push_back(AlignString("Latest SSID: ", ' ', 2, 16) + tng->GetName(net)); } } else { td->push_back(AlignString("", ' ', 2, 16) + "No SSID data seen"); } } if (net->ssid_map.size() > 0) { td->push_back(""); for (map::iterator s = net->ssid_map.begin(); s != net->ssid_map.end(); ++s) { AppendSSIDInfo(td, net, s->second); td->push_back(""); } } } if (net->snrdata.last_signal_dbm == -256 || net->snrdata.last_signal_dbm == 0) { if (net->snrdata.last_signal_rssi == 0) { td->push_back(AlignString("Signal: ", ' ', 2, 16) + "No signal data available"); } else { osstr.str(""); osstr << net->snrdata.last_signal_rssi << " RSSI (max " << net->snrdata.max_signal_rssi << " RSSI)"; td->push_back(AlignString("Signal: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << net->snrdata.last_noise_rssi << " RSSI (max " << net->snrdata.max_noise_rssi << " RSSI)"; td->push_back(AlignString("Noise: ", ' ', 2, 16) + osstr.str()); } } else { osstr.str(""); osstr << net->snrdata.last_signal_dbm << "dBm (max " << net->snrdata.max_signal_dbm << "dBm)"; td->push_back(AlignString("Signal: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << net->snrdata.last_noise_dbm << "dBm (max " << net->snrdata.max_noise_dbm << "dBm)"; td->push_back(AlignString("Noise: ", ' ', 2, 16) + osstr.str()); } if (net->data_cryptset != 0) { osstr.str(crypt_to_str(net->data_cryptset)); td->push_back(AlignString("Data Crypt: ", ' ', 2, 16) + osstr.str()); td->push_back(AlignString(" ", ' ', 2, 16) + "( Data encryption seen " "by BSSID )"); } td->push_back(AlignString("Packets: ", ' ', 2, 16) + IntToString(net->llc_packets + net->data_packets)); td->push_back(AlignString("Data Packets: ", ' ', 2, 16) + IntToString(net->data_packets)); td->push_back(AlignString("Mgmt Packets: ", ' ', 2, 16) + IntToString(net->llc_packets)); td->push_back(AlignString("Crypt Packets: ", ' ', 2, 16) + IntToString(net->crypt_packets)); td->push_back(AlignString("Fragments: ", ' ', 2, 16) + IntToString(net->fragments) + "/sec"); td->push_back(AlignString("Retries: ", ' ', 2, 16) + IntToString(net->retries) + "/sec"); osstr.str(""); if (net->datasize < 1024) osstr << net->datasize << "B"; else if (net->datasize < (1024 * 1024)) osstr << (int) (net->datasize / 1024) << "K"; else osstr << (int) (net->datasize / 1024 / 1024) << "M"; td->push_back(AlignString("Data Size: ", ' ', 2, 16) + osstr.str()); if (net->guess_ipdata.ip_type >= ipdata_factoryguess && net->guess_ipdata.ip_type <= ipdata_group) { td->push_back(""); osstr.str(""); switch (net->guess_ipdata.ip_type) { case ipdata_group: osstr << "Aggregated"; break; case ipdata_udptcp: osstr << "UDP/TCP"; break; case ipdata_arp: osstr << "ARP"; break; case ipdata_dhcp: osstr << "DHCP"; break; default: osstr << "Unknown"; break; } td->push_back(AlignString("IP Type: ", ' ', 2, 16) + osstr.str()); td->push_back(AlignString("IP Address: ", ' ', 2, 16) + string(inet_ntoa(net->guess_ipdata.ip_addr_block))); if (net->guess_ipdata.ip_netmask.s_addr != 0) td->push_back(AlignString("IP Netmask: ", ' ', 2, 16) + string(inet_ntoa(net->guess_ipdata.ip_netmask))); if (net->guess_ipdata.ip_gateway.s_addr != 0) td->push_back(AlignString("IP Gateway: ", ' ', 2, 16) + string(inet_ntoa(net->guess_ipdata.ip_gateway))); td->push_back(""); } map *cardmap = kpinterface->FetchNetCardMap(); map::iterator kci; for (map::iterator sdi = net->source_map.begin(); sdi != net->source_map.end(); ++sdi) { if ((kci = cardmap->find(sdi->second->source_uuid)) == cardmap->end()) { td->push_back(AlignString("Seen By: ", ' ', 2, 16) + "(Unknown Source) " + sdi->second->source_uuid.UUID2String()); } else { td->push_back(AlignString("Seen By: ", ' ', 2, 16) + kci->second->name + " (" + kci->second->interface + ") " + sdi->second->source_uuid.UUID2String()); } osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(sdi->second->last_seen)) + 4).substr(0, 15)); td->push_back(AlignString("", ' ', 2, 16) + osstr.str()); } if (net->cdp_dev_id.length() > 0) { td->push_back(AlignString("CDP Device: ", ' ', 2, 16) + net->cdp_dev_id); td->push_back(AlignString("CDP Port: ", ' ', 2, 16) + net->cdp_port_id); } for (map::const_iterator ai = net->arb_tag_map.begin(); ai != net->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; td->push_back(AlignString(ai->first + ": ", ' ', 2, 16) + ai->second); } if (netvec == NULL) return 1; if (netvec->size() == 1) return 1; for (unsigned int x = 0; x < netvec->size(); x++) { td->push_back(""); AppendNetworkInfo(td, NULL, (*netvec)[x]); } return 1; } int Kis_NetDetails_Panel::GraphTimer() { Kis_Display_NetGroup *tng, *ldng; Netracker::tracked_network *meta, *tmeta; int update = 0; if (kpinterface == NULL) return 1; ldng = dng; tng = kpinterface->FetchMainPanel()->FetchSelectedNetgroup(); if (tng != NULL) { if (ldng == NULL) { ldng = tng; update = 1; } else { meta = ldng->FetchNetwork(); tmeta = tng->FetchNetwork(); if (meta == NULL && tmeta != NULL) { ldng = tng; update = 1; } else if (tmeta != NULL && last_mac != tmeta->bssid) { ClearGraphVectors(); return 1; } else if (meta != NULL && last_dirty < meta->last_time) { update = 1; } } } else if (ldng != NULL) { ClearGraphVectors(); } if (update && ldng != NULL) { meta = ldng->FetchNetwork(); UpdateGraphVectors(meta->snrdata.last_signal_dbm == -256 ? meta->snrdata.last_signal_rssi : meta->snrdata.last_signal_dbm, meta->llc_packets + meta->data_packets, meta->retries); } return 1; } void Kis_NetDetails_Panel::DrawPanel() { Kis_Display_NetGroup *tng; Netracker::tracked_network *meta, *tmeta; int update = 0; vector td; ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); // Figure out if we've changed tng = kpinterface->FetchMainPanel()->FetchSelectedNetgroup(); if (tng != NULL) { if (dng == NULL) { dng = tng; update = 1; } else { meta = dng->FetchNetwork(); tmeta = tng->FetchNetwork(); if (meta == NULL && tmeta != NULL) { // We didn't have a valid metagroup before - we get the new one dng = tng; update = 1; } else if (tmeta != NULL && last_mac != tmeta->bssid) { // We weren't the same network before - we get the new one, clear the // graph vectors dng = tng; ClearGraphVectors(); update = 1; } else if (meta != NULL && last_dirty < meta->last_time) { // The network has changed time - just update update = 1; } } } else if (dng != NULL) { // We've lost a selected network entirely, drop to null and update, clear the // graph vectors dng = NULL; ClearGraphVectors(); update = 1; } if (dng == NULL) { if ((dng = kpinterface->FetchMainPanel()->FetchSelectedNetgroup()) == NULL) { kpinterface->RaiseAlert("No network", "Cannot view details, no network was selected.\n" "Set the Sort type to anything besides Auto-Fit\n" "and highlight a network, then view details.\n"); kpinterface->KillPanel(this); return; } Netracker::tracked_network *meta = dng->FetchNetwork(); if (meta == NULL) { kpinterface->RaiseAlert("No network", "Cannot view details, no network was selected.\n" "Set the Sort type to anything besides Auto-Fit\n" "and highlight a network, then view details.\n"); kpinterface->KillPanel(this); return; } } if (update) { if (dng != NULL) meta = dng->FetchNetwork(); else meta = NULL; td.clear(); if (dng != NULL) { AppendNetworkInfo(&td, tng, NULL); } else { td.push_back("No network selected"); td.push_back("Change sort order to anything other than \"Auto Fit\""); td.push_back("and highlight a network."); } } netdetailt->SetText(td); DrawComponentVec(); wmove(win, 0, 0); } void Kis_NetDetails_Panel::ButtonAction(Kis_Panel_Component *in_button) { if (in_button == closebutton) { globalreg->panel_interface->KillPanel(this); } else if (in_button == nextbutton) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_DOWN); dng = NULL; } else if (in_button == prevbutton) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_UP); dng = NULL; } } void Kis_NetDetails_Panel::MenuAction(int opt) { // Menu processed an event, do something with it if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } else if (opt == mi_addnote) { Kis_AddNetNote_Panel *np = new Kis_AddNetNote_Panel(globalreg, kpinterface); kpinterface->AddPanel(np); } else if (opt == mi_nextnet) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_DOWN); dng = NULL; return; } else if (opt == mi_prevnet) { kpinterface->FetchMainPanel()->FetchDisplayNetlist()->KeyPress(KEY_UP); dng = NULL; return; } else if (opt == mi_clients) { Kis_Clientlist_Panel *cl = new Kis_Clientlist_Panel(globalreg, kpinterface); kpinterface->AddPanel(cl); } else if (opt == mi_net || opt == mi_graphsig || opt == mi_graphpacket || opt == mi_graphretry) { UpdateViewMenu(opt); } } void Kis_NetDetails_Panel::UpdateViewMenu(int mi) { string opt; if (mi == mi_net) { opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWNET"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("DETAILS_SHOWNET", "false", 1); menu->SetMenuItemChecked(mi_net, 0); netdetailt->Hide(); } else { kpinterface->prefs->SetOpt("DETAILS_SHOWNET", "true", 1); menu->SetMenuItemChecked(mi_net, 1); netdetailt->Show(); } } else if (mi == mi_graphsig) { opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHSIG"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHSIG", "false", 1); menu->SetMenuItemChecked(mi_graphsig, 0); siggraph->Hide(); } else { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHSIG", "true", 1); menu->SetMenuItemChecked(mi_graphsig, 1); siggraph->Show(); } } else if (mi == mi_graphpacket) { opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHPACKET"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHPACKET", "false", 1); menu->SetMenuItemChecked(mi_graphpacket, 0); packetgraph->Hide(); } else { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHPACKET", "true", 1); menu->SetMenuItemChecked(mi_graphpacket, 1); packetgraph->Show(); } } else if (mi == mi_graphretry) { opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHRETRY"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHRETRY", "false", 1); menu->SetMenuItemChecked(mi_graphretry, 0); retrygraph->Hide(); } else { kpinterface->prefs->SetOpt("DETAILS_SHOWGRAPHRETRY", "true", 1); menu->SetMenuItemChecked(mi_graphretry, 1); retrygraph->Show(); } } else if (mi == -1) { opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWNET"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_net, 1); netdetailt->Show(); } else { menu->SetMenuItemChecked(mi_net, 0); netdetailt->Hide(); } opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHSIG"); if (opt == "true") { menu->SetMenuItemChecked(mi_graphsig, 1); siggraph->Show(); } else { menu->SetMenuItemChecked(mi_graphsig, 0); siggraph->Hide(); } opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHPACKET"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_graphpacket, 1); packetgraph->Show(); } else { menu->SetMenuItemChecked(mi_graphpacket, 0); packetgraph->Hide(); } opt = kpinterface->prefs->FetchOpt("DETAILS_SHOWGRAPHRETRY"); if (opt == "true") { menu->SetMenuItemChecked(mi_graphretry, 1); retrygraph->Show(); } else { menu->SetMenuItemChecked(mi_graphretry, 0); retrygraph->Hide(); } } } int ChanDetailsButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ChanDetails_Panel *) aux)->ButtonAction(component); return 1; } int ChanDetailsMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ChanDetails_Panel *) aux)->MenuAction(status); return 1; } int ChanDetailsGraphEvent(TIMEEVENT_PARMS) { ((Kis_ChanDetails_Panel *) parm)->GraphTimer(); return 1; } void ChanDetailsCliConfigured(CLICONF_CB_PARMS) { ((Kis_ChanDetails_Panel *) auxptr)->NetClientConfigured(kcli, recon); } void ChanDetailsCliAdd(KPI_ADDCLI_CB_PARMS) { ((Kis_ChanDetails_Panel *) auxptr)->NetClientAdd(netcli, add); } void ChanDetailsProtoCHANNEL(CLIPROTO_CB_PARMS) { ((Kis_ChanDetails_Panel *) auxptr)->Proto_CHANNEL(globalreg, proto_string, proto_parsed, srccli, auxptr); } Kis_ChanDetails_Panel::Kis_ChanDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { grapheventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &ChanDetailsGraphEvent, (void *) this); menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, ChanDetailsMenuCB, this); mn_channels = menu->AddMenu("Channels", 0); mi_close = menu->AddMenuItem("Close window", mn_channels, 'w'); mn_view = menu->AddMenu("View", 0); mi_chansummary = menu->AddMenuItem("Channel Summary", mn_view, 'c'); menu->AddMenuItem("-", mn_view, 0); mi_signal = menu->AddMenuItem("Signal Level", mn_view, 's'); mi_packets = menu->AddMenuItem("Packet Rate", mn_view, 'p'); mi_traffic = menu->AddMenuItem("Data", mn_view, 'd'); mi_networks = menu->AddMenuItem("Networks", mn_view, 'n'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); // Channel summary list gets titles but doesn't get the current one highlighted // and locks to fit inside the window chansummary = new Kis_Scrollable_Table(globalreg, this); chansummary->SetHighlightSelected(0); chansummary->SetLockScrollTop(1); chansummary->SetDrawTitles(1); AddComponentVec(chansummary, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); // Populate the titles vector titles; Kis_Scrollable_Table::title_data t; t.width = 4; t.title = "Chan"; t.alignment = 0; titles.push_back(t); t.width = 7; t.title = "Packets"; t.alignment = 2; titles.push_back(t); t.width = 3; t.title = "P/S"; t.alignment = 2; titles.push_back(t); t.width = 5; t.title = "Data"; t.alignment = 2; titles.push_back(t); t.width = 4; t.title = "Dt/s"; t.alignment = 2; titles.push_back(t); t.width = 4; t.title = "Netw"; t.alignment = 2; titles.push_back(t); t.width = 4; t.title = "ActN"; t.alignment = 2; titles.push_back(t); t.width = 6; t.title = "Time"; t.alignment = 2; titles.push_back(t); chansummary->AddTitles(titles); chansummary->Show(); siggraph = new Kis_IntGraph(globalreg, this); siggraph->SetName("CHANNEL_SIG"); siggraph->SetPreferredSize(0, 12); siggraph->SetScale(-110, -20); siggraph->SetInterpolation(0); siggraph->SetMode(0); siggraph->Show(); siggraph->AddExtDataVec("Signal", 3, "channel_sig", "yellow,yellow", ' ', ' ', 1, &sigvec); siggraph->AddExtDataVec("Noise", 4, "channel_noise", "green,green", ' ', ' ', 1, &noisevec); // AddComponentVec(siggraph, KIS_PANEL_COMP_DRAW); packetgraph = new Kis_IntGraph(globalreg, this); packetgraph->SetName("CHANNEL_PPS"); packetgraph->SetPreferredSize(0, 12); packetgraph->SetInterpolation(0); packetgraph->SetMode(0); packetgraph->Show(); packetgraph->AddExtDataVec("Packet Rate", 4, "channel_pps", "green,green", ' ', ' ', 1, &packvec); // AddComponentVec(packetgraph, KIS_PANEL_COMP_DRAW); bytegraph = new Kis_IntGraph(globalreg, this); bytegraph->SetName("CHANNEL_BPS"); bytegraph->SetPreferredSize(0, 12); bytegraph->SetInterpolation(0); bytegraph->SetMode(0); bytegraph->Show(); bytegraph->AddExtDataVec("Traffic", 4, "channel_bytes", "green,green", ' ', ' ', 1, &bytevec); // AddComponentVec(bytegraph, KIS_PANEL_COMP_DRAW); netgraph = new Kis_IntGraph(globalreg, this); netgraph->SetName("CHANNEL_NETS"); netgraph->SetPreferredSize(0, 12); netgraph->SetInterpolation(0); netgraph->SetMode(0); netgraph->Show(); netgraph->AddExtDataVec("Networks", 3, "channel_nets", "yellow,yellow", ' ', ' ', 1, &netvec); netgraph->AddExtDataVec("Active", 4, "channel_actnets", "green,green", ' ', ' ', 1, &anetvec); // AddComponentVec(netgraph, KIS_PANEL_COMP_DRAW); SetTitle(""); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(siggraph, 0, 0); vbox->Pack_End(packetgraph, 0, 0); vbox->Pack_End(bytegraph, 0, 0); vbox->Pack_End(netgraph, 0, 0); vbox->Pack_End(chansummary, 0, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); SetActiveComponent(chansummary); UpdateViewMenu(-1); GraphTimer(); addref = kpinterface->Add_NetCli_AddCli_CB(ChanDetailsCliAdd, (void *) this); main_component = vbox; Position(WIN_CENTER(LINES, COLS)); } Kis_ChanDetails_Panel::~Kis_ChanDetails_Panel() { kpinterface->Remove_Netcli_AddCli_CB(addref); kpinterface->Remove_All_Netcli_Conf_CB(ChanDetailsCliConfigured); kpinterface->Remove_All_Netcli_ProtoHandler("CHANNEL", ChanDetailsProtoCHANNEL, this); globalreg->timetracker->RemoveTimer(grapheventid); } void Kis_ChanDetails_Panel::NetClientConfigured(KisNetClient *in_cli, int in_recon) { if (in_cli->RegisterProtoHandler("CHANNEL", KCLI_CHANDETAILS_CHANNEL_FIELDS, ChanDetailsProtoCHANNEL, this) < 0) { _MSG("Could not register CHANNEL protocol with remote server, connection " "will be terminated", MSGFLAG_ERROR); in_cli->KillConnection(); } } void Kis_ChanDetails_Panel::NetClientAdd(KisNetClient *in_cli, int add) { if (add == 0) return; in_cli->AddConfCallback(ChanDetailsCliConfigured, 1, this); } int Kis_ChanDetails_Panel::GraphTimer() { // Translates the channel map we get from the server into int vectors for // the graphs, also populates the channel labels with the channel #s at // the appropriate positions. // // Also rewrites the channel summary table w/ the new data // // All in all this is a really expensive timer, but we only do it inside // the channel display window and its in the UI, so screw it // Update the vectors sigvec.clear(); noisevec.clear(); packvec.clear(); bytevec.clear(); netvec.clear(); anetvec.clear(); graph_label_vec.clear(); chansummary->Clear(); unsigned int chpos = 0; unsigned int tpos = 0; for (map::iterator x = channel_map.begin(); x != channel_map.end(); ++x) { if (x->second->sig_rssi != 0) { sigvec.push_back(x->second->sig_rssi); noisevec.push_back(x->second->noise_rssi); } else if (x->second->sig_dbm != 0) { sigvec.push_back(x->second->sig_dbm); if (x->second->noise_dbm == 0) noisevec.push_back(-256); else noisevec.push_back(x->second->noise_dbm); } else { sigvec.push_back(-256); noisevec.push_back(-256); } packvec.push_back(x->second->packets_delta); bytevec.push_back(x->second->bytes_delta); netvec.push_back(x->second->networks); anetvec.push_back(x->second->networks_active); Kis_IntGraph::graph_label lab; lab.position = chpos++; lab.label = IntToString(x->first); graph_label_vec.push_back(lab); // Populate the channel info table vector td; td.push_back(IntToString(x->first)); td.push_back(IntToString(x->second->packets)); td.push_back(IntToString(x->second->packets_delta)); if (x->second->bytes_seen < 1024) { td.push_back(IntToString(x->second->bytes_seen) + "B"); } else if (x->second->bytes_seen < (1024 * 1024)) { td.push_back(IntToString(x->second->bytes_seen / 1024) + "K"); } else { td.push_back(IntToString(x->second->bytes_seen / 1024 / 1024) + "M"); } if (x->second->bytes_delta < 1024) { td.push_back(IntToString(x->second->bytes_delta) + "B"); } else if (x->second->bytes_delta < (1024 * 1024)) { td.push_back(IntToString(x->second->bytes_delta / 1024) + "K"); } else { td.push_back(IntToString(x->second->bytes_delta / 1024 / 1024) + "M"); } td.push_back(IntToString(x->second->networks)); td.push_back(IntToString(x->second->networks_active)); td.push_back(NtoString((float) x->second->channel_time_on / 1000000).Str() + "s"); chansummary->AddRow(tpos++, td); } siggraph->SetXLabels(graph_label_vec, "Signal"); packetgraph->SetXLabels(graph_label_vec, "Packet Rate"); bytegraph->SetXLabels(graph_label_vec, "Traffic"); netgraph->SetXLabels(graph_label_vec, "Networks"); return 1; } void Kis_ChanDetails_Panel::DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); DrawComponentVec(); wmove(win, 0, 0); } void Kis_ChanDetails_Panel::ButtonAction(Kis_Panel_Component *in_button) { return; } void Kis_ChanDetails_Panel::MenuAction(int opt) { if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } else { UpdateViewMenu(opt); } } void Kis_ChanDetails_Panel::UpdateViewMenu(int mi) { string opt; if (mi == mi_chansummary) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWSUM"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWSUM", "false", 1); menu->SetMenuItemChecked(mi_chansummary, 0); chansummary->Hide(); } else { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWSUM", "true", 1); menu->SetMenuItemChecked(mi_chansummary, 1); chansummary->Show(); } } else if (mi == mi_signal) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWSIG"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWSIG", "false", 1); menu->SetMenuItemChecked(mi_signal, 0); siggraph->Hide(); } else { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWSIG", "true", 1); menu->SetMenuItemChecked(mi_signal, 1); siggraph->Show(); } } else if (mi == mi_packets) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWPACK"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWPACK", "false", 1); menu->SetMenuItemChecked(mi_packets, 0); packetgraph->Hide(); } else { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWPACK", "true", 1); menu->SetMenuItemChecked(mi_packets, 1); packetgraph->Show(); } } else if (mi == mi_traffic) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWTRAF"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWTRAF", "false", 1); menu->SetMenuItemChecked(mi_traffic, 0); bytegraph->Hide(); } else { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWTRAF", "true", 1); menu->SetMenuItemChecked(mi_traffic, 1); bytegraph->Show(); } } else if (mi == mi_networks) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWNET"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWNET", "false", 1); menu->SetMenuItemChecked(mi_networks, 0); netgraph->Hide(); } else { kpinterface->prefs->SetOpt("CHANDETAILS_SHOWNET", "true", 1); menu->SetMenuItemChecked(mi_networks, 1); netgraph->Show(); } } else if (mi == -1) { opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWSUM"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_chansummary, 1); chansummary->Show(); } else { menu->SetMenuItemChecked(mi_chansummary, 0); chansummary->Hide(); } opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWSIG"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_signal, 1); siggraph->Show(); } else { menu->SetMenuItemChecked(mi_signal, 0); siggraph->Hide(); } opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWPACK"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_packets, 1); packetgraph->Show(); } else { menu->SetMenuItemChecked(mi_packets, 0); packetgraph->Hide(); } opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWTRAF"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_traffic, 1); bytegraph->Show(); } else { menu->SetMenuItemChecked(mi_traffic, 0); bytegraph->Hide(); } opt = kpinterface->prefs->FetchOpt("CHANDETAILS_SHOWNET"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_networks, 1); netgraph->Show(); } else { menu->SetMenuItemChecked(mi_networks, 0); netgraph->Hide(); } } } void Kis_ChanDetails_Panel::Proto_CHANNEL(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < KCLI_CHANDETAILS_CHANNEL_NUMFIELDS) return; int fnum = 0; chan_sig_info *ci; int tint; long int tlong; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { return; } if (channel_map.find(tint) != channel_map.end()) { ci = channel_map[tint]; } else { ci = new chan_sig_info; ci->channel = tint; channel_map[tint] = ci; } ci->last_updated = time(0); if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; if (tint != 0) ci->channel_time_on = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->packets = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; if (tint != 0) ci->packets_delta = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%ld", &tlong) != 1) return; ci->usec_used = tlong; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%ld", &tlong) != 1) return; ci->bytes_seen = tlong; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%ld", &tlong) != 1) return; if (tlong != 0) ci->bytes_delta = tlong; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->networks = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->networks_active = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->sig_dbm = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->sig_rssi = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->noise_dbm = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; ci->noise_rssi = tint; } int CliDetailsButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ClientDetails_Panel *) aux)->ButtonAction(component); return 1; } int CliDetailsMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_ClientDetails_Panel *) aux)->MenuAction(status); return 1; } int CliDetailsGraphEvent(TIMEEVENT_PARMS) { return ((Kis_ClientDetails_Panel *) parm)->GraphTimer(); } Kis_ClientDetails_Panel::Kis_ClientDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { grapheventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &CliDetailsGraphEvent, (void *) this); menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, CliDetailsMenuCB, this); mn_client = menu->AddMenu("Client", 0); mi_addnote = menu->AddMenuItem("Client Note...", mn_client, 'N'); menu->AddMenuItem("-", mn_client, 0); mi_nextcli = menu->AddMenuItem("Next client", mn_client, 'n'); mi_prevcli = menu->AddMenuItem("Prev client", mn_client, 'p'); menu->AddMenuItem("-", mn_client, 0); mi_close = menu->AddMenuItem("Close window", mn_client, 'w'); mn_view = menu->AddMenu("View", 0); mi_cli = menu->AddMenuItem("Client Details", mn_view, 'c'); menu->AddMenuItem("-", mn_view, 0); mi_graphsig = menu->AddMenuItem("Signal Level", mn_view, 's'); mi_graphpacket = menu->AddMenuItem("Packet Rate", mn_view, 'p'); mi_graphretry = menu->AddMenuItem("Retry Rate", mn_view, 'r'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); clientdetailt = new Kis_Free_Text(globalreg, this); AddComponentVec(clientdetailt, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); clientdetailt->Show(); siggraph = new Kis_IntGraph(globalreg, this); siggraph->SetName("DETAIL_SIG"); siggraph->SetPreferredSize(0, 8); siggraph->SetScale(-110, -40); siggraph->SetInterpolation(1); siggraph->SetMode(0); siggraph->Show(); siggraph->AddExtDataVec("Signal", 4, "graph_detail_sig", "yellow,yellow", ' ', ' ', 1, &sigpoints); AddComponentVec(siggraph, KIS_PANEL_COMP_EVT); packetgraph = new Kis_IntGraph(globalreg, this); packetgraph->SetName("DETAIL_PPS"); packetgraph->SetPreferredSize(0, 8); packetgraph->SetScale(0, 0); packetgraph->SetInterpolation(1); packetgraph->SetMode(0); packetgraph->Show(); packetgraph->AddExtDataVec("Packet Rate", 4, "graph_detail_pps", "green,green", ' ', ' ', 1, &packetpps); AddComponentVec(packetgraph, KIS_PANEL_COMP_EVT); retrygraph = new Kis_IntGraph(globalreg, this); retrygraph->SetName("DETAIL_RETRY_PPS"); retrygraph->SetPreferredSize(0, 8); retrygraph->SetScale(0, 0); retrygraph->SetInterpolation(1); retrygraph->SetMode(0); retrygraph->Show(); retrygraph->AddExtDataVec("Retry Rate", 4, "graph_detail_retrypps", "red,red", ' ', ' ', 1, &retrypps); AddComponentVec(retrygraph, KIS_PANEL_COMP_EVT); ClearGraphVectors(); SetTitle(""); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(siggraph, 0, 0); vbox->Pack_End(packetgraph, 0, 0); vbox->Pack_End(retrygraph, 0, 0); vbox->Pack_End(clientdetailt, 1, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); last_dirty = 0; last_mac = mac_addr(0); dng = NULL; dcli = NULL; vector td; td.push_back("No client selected"); td.push_back("Change client list sort order to something other than "); td.push_back("\"Autofit\" and select a client."); clientdetailt->SetText(td); main_component = vbox; SetActiveComponent(clientdetailt); clientlist = NULL; UpdateViewMenu(-1); Position(WIN_CENTER(LINES, COLS)); } Kis_ClientDetails_Panel::~Kis_ClientDetails_Panel() { if (grapheventid >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(grapheventid); } void Kis_ClientDetails_Panel::ClearGraphVectors() { lastpackets = 0; sigpoints.clear(); packetpps.clear(); retrypps.clear(); for (unsigned int x = 0; x < 120; x++) { sigpoints.push_back(-256); packetpps.push_back(0); retrypps.push_back(0); } } void Kis_ClientDetails_Panel::UpdateGraphVectors(int signal, int pps, int retry) { sigpoints.push_back(signal); if (sigpoints.size() > 120) sigpoints.erase(sigpoints.begin(), sigpoints.begin() + sigpoints.size() - 120); if (lastpackets == 0) lastpackets = pps; packetpps.push_back(pps - lastpackets); lastpackets = pps; if (packetpps.size() > 120) packetpps.erase(packetpps.begin(), packetpps.begin() + packetpps.size() - 120); retrypps.push_back(retry); if (retrypps.size() > 120) retrypps.erase(retrypps.begin(), retrypps.begin() + retrypps.size() - 120); } int Kis_ClientDetails_Panel::GraphTimer() { Netracker::tracked_client *ldcli; if (clientlist == NULL) return 1; if (kpinterface == NULL) return 1; ldcli = clientlist->FetchSelectedClient(); if (ldcli != NULL) { if (ldcli != dcli) ClearGraphVectors(); } else { ClearGraphVectors(); return 1; } UpdateGraphVectors(ldcli->snrdata.last_signal_dbm == -256 ? ldcli->snrdata.last_signal_rssi : ldcli->snrdata.last_signal_dbm, ldcli->llc_packets + ldcli->data_packets, ldcli->retries); return 1; } void Kis_ClientDetails_Panel::DrawPanel() { Netracker::tracked_client *tcli = NULL; int update = 0; vector td; ostringstream osstr; ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); if (clientlist != NULL) { tcli = clientlist->FetchSelectedClient(); if (tcli == NULL) { dcli = tcli; update = 1; ClearGraphVectors(); } else if (tcli != dcli) { dcli = tcli; update = 1; ClearGraphVectors(); } else { if (dcli->last_time != last_dirty) update = 1; } } else if (dcli != NULL) { dcli = NULL; update = 1; ClearGraphVectors(); } if (update) { if (dcli != NULL) { td.push_back(AlignString("MAC Address: ", ' ', 2, 16) + dcli->mac.Mac2String()); td.push_back(AlignString("Manuf: ", ' ', 2, 16) + dcli->manuf); td.push_back(AlignString("Network: ", ' ', 2, 16) + dcli->bssid.Mac2String()); if (dcli->netptr != NULL) { if (dcli->netptr->lastssid != NULL && dcli->netptr->lastssid->ssid != "") { td.push_back(AlignString("Net SSID: ", ' ', 2, 16) + dcli->netptr->lastssid->ssid); } td.push_back(AlignString("Net Manuf: ", ' ', 2, 16) + dcli->netptr->manuf); } osstr.str(""); if (dcli->type == client_unknown) osstr << "Unknown"; else if (dcli->type == client_fromds) osstr << "Wired (traffic from AP only)"; else if (dcli->type == client_tods) osstr << "Wireless (traffic from wireless only)"; else if (dcli->type == client_interds) osstr << "Inter-AP traffic (WDS)"; else if (dcli->type == client_established) osstr << "Wireless (traffic to and from AP)"; else if (dcli->type == client_adhoc) osstr << "Wireless Ad-Hoc"; td.push_back(AlignString("Type: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(dcli->first_time)) + 4).substr(0, 15)); td.push_back(AlignString("First Seen: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(dcli->last_time)) + 4).substr(0, 15)); td.push_back(AlignString("Last Seen: ", ' ', 2, 16) + osstr.str()); if (dcli->ssid_map.size() > 0) { td.push_back(""); for (map::iterator si = dcli->ssid_map.begin(); si != dcli->ssid_map.end(); ++si) { osstr.str(""); if (si->second->ssid == "") osstr << "(Broadcast request) "; else osstr << si->second->ssid << " "; td.push_back(AlignString("Probed Network: ", ' ', 2, 16) + osstr.str()); osstr.str(crypt_to_str(si->second->cryptset)); td.push_back(AlignString("Encryption: ", ' ', 2, 18) + osstr.str()); osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(si->second->last_time)) + 4).substr(0, 15)); td.push_back(AlignString("Last Probed: ", ' ', 2, 18) + osstr.str()); td.push_back(""); } } td.push_back(AlignString("Decrypted: ", ' ', 2, 16) + (dcli->decrypted ? "Yes" : "No")); for (map::const_iterator fmi = dcli->freq_mhz_map.begin(); fmi != dcli->freq_mhz_map.end(); ++fmi) { float perc = ((float) fmi->second / (float) (dcli->llc_packets + dcli->data_packets)) * 100; int ch = FreqToChan(fmi->first); ostringstream chtxt; if (ch != 0) chtxt << ch; else chtxt << "Unk"; osstr.str(""); osstr << fmi->first << " (" << chtxt.str() << ") - " << fmi->second << " packets, " << NtoString(perc, 2).Str() << "%"; td.push_back(AlignString(fmi == dcli->freq_mhz_map.begin() ? "Frequency: " : "", ' ', 2, 16) + osstr.str()); } if (dcli->snrdata.last_signal_dbm == -256 || dcli->snrdata.last_signal_dbm == 0) { if (dcli->snrdata.last_signal_rssi == 0) { td.push_back(AlignString("Signal: ", ' ', 2, 16) + "No signal data available"); } else { osstr.str(""); osstr << dcli->snrdata.last_signal_rssi << " RSSI (max " << dcli->snrdata.max_signal_rssi << " RSSI)"; td.push_back(AlignString("Signal: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->snrdata.last_noise_rssi << " RSSI (max " << dcli->snrdata.max_noise_rssi << " RSSI)"; td.push_back(AlignString("Noise: ", ' ', 2, 16) + osstr.str()); } } else { osstr.str(""); osstr << dcli->snrdata.last_signal_dbm << "dBm (max " << dcli->snrdata.max_signal_dbm << "dBm)"; td.push_back(AlignString("Signal: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->snrdata.last_noise_dbm << "dBm (max " << dcli->snrdata.max_noise_dbm << "dBm)"; td.push_back(AlignString("Noise: ", ' ', 2, 16) + osstr.str()); } if (dcli->data_cryptset != 0) { osstr.str(crypt_to_str(dcli->data_cryptset)); td.push_back(AlignString("Data Crypt: ", ' ', 2, 16) + osstr.str()); td.push_back(AlignString(" ", ' ', 2, 16) + "( Data encryption " "seen by client )"); } osstr.str(""); osstr << dcli->llc_packets + dcli->data_packets; td.push_back(AlignString("Packets: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->data_packets; td.push_back(AlignString("Data Packets: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->llc_packets; td.push_back(AlignString("Mgmt Packets: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->crypt_packets; td.push_back(AlignString("Crypt Packets: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->fragments << "/sec"; td.push_back(AlignString("Fragments: ", ' ', 2, 16) + osstr.str()); osstr.str(""); osstr << dcli->retries << "/sec"; td.push_back(AlignString("Retries: ", ' ', 2, 16) + osstr.str()); osstr.str(""); if (dcli->datasize < 1024) osstr << dcli->datasize << "B"; else if (dcli->datasize < (1024 * 1024)) osstr << (int) (dcli->datasize / 1024) << "K"; else osstr << (int) (dcli->datasize / 1024 / 1024) << "M"; td.push_back(AlignString("Data Size: ", ' ', 2, 16) + osstr.str()); map *cardmap = kpinterface->FetchNetCardMap(); map::iterator kci; for (map::iterator sdi = dcli->source_map.begin(); sdi != dcli->source_map.end(); ++sdi) { if ((kci = cardmap->find(sdi->second->source_uuid)) == cardmap->end()) { td.push_back(AlignString("Seen By: ", ' ', 2, 16) + "(Unknown Source) " + sdi->second->source_uuid.UUID2String()); } else { td.push_back(AlignString("Seen By: ", ' ', 2, 16) + kci->second->name + " (" + kci->second->interface + ") " + sdi->second->source_uuid.UUID2String()); } osstr.str(""); osstr << setw(14) << left << (string(ctime((const time_t *) &(sdi->second->last_seen)) + 4).substr(0, 15)); td.push_back(AlignString("", ' ', 2, 16) + osstr.str()); } if (dcli->cdp_dev_id.length() > 0) { td.push_back(AlignString("CDP Device: ", ' ', 2, 16) + dcli->cdp_dev_id); td.push_back(AlignString("CDP Port: ", ' ', 2, 16) + dcli->cdp_port_id); } if (dcli->dhcp_host.length() > 0) { td.push_back(AlignString("DHCP Name: ", ' ', 2, 16) + dcli->dhcp_host); } if (dcli->dhcp_vendor.length() > 0) { td.push_back(AlignString("DHCP OS: ", ' ', 2, 16) + dcli->dhcp_vendor); } if (dcli->guess_ipdata.ip_type > ipdata_factoryguess && dcli->guess_ipdata.ip_type < ipdata_group) { td.push_back(""); osstr.str(""); switch (dcli->guess_ipdata.ip_type) { case ipdata_udptcp: osstr << "UDP/TCP"; break; case ipdata_arp: osstr << "ARP"; break; case ipdata_dhcp: osstr << "DHCP"; break; default: osstr << "Unknown"; break; } td.push_back(AlignString("IP Type: ", ' ', 2, 16) + osstr.str()); td.push_back(AlignString("IP Address: ", ' ', 2, 16) + string(inet_ntoa(dcli->guess_ipdata.ip_addr_block))); if (dcli->guess_ipdata.ip_netmask.s_addr != 0) td.push_back(AlignString("IP Netmask: ", ' ', 2, 16) + string(inet_ntoa(dcli->guess_ipdata.ip_netmask))); if (dcli->guess_ipdata.ip_gateway.s_addr != 0) td.push_back(AlignString("IP Gateway: ", ' ', 2, 16) + string(inet_ntoa(dcli->guess_ipdata.ip_gateway))); td.push_back(""); } for (map::const_iterator ai = dcli->arb_tag_map.begin(); ai != dcli->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; td.push_back(AlignString(ai->first + ": ", ' ', 2, 16) + ai->second); } } } clientdetailt->SetText(td); DrawComponentVec(); wmove(win, 0, 0); } void Kis_ClientDetails_Panel::ButtonAction(Kis_Panel_Component *in_button) { return; } void Kis_ClientDetails_Panel::MenuAction(int opt) { if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } else if (opt == mi_addnote) { Kis_AddCliNote_Panel *np = new Kis_AddCliNote_Panel(globalreg, kpinterface); np->SetClient(dcli); kpinterface->AddPanel(np); return; } else if (opt == mi_nextcli && clientlist != NULL) { clientlist->KeyPress(KEY_DOWN); dcli = NULL; return; } else if (opt == mi_prevcli && clientlist != NULL) { clientlist->KeyPress(KEY_UP); dcli = NULL; return; } else if (opt == mi_cli || opt == mi_graphsig || opt == mi_graphpacket || opt == mi_graphretry) { UpdateViewMenu(opt); return; } } void Kis_ClientDetails_Panel::UpdateViewMenu(int mi) { string opt; if (mi == mi_cli) { opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWCLI"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWCLI", "false", 1); menu->SetMenuItemChecked(mi_cli, 0); clientdetailt->Hide(); } else { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWCLI", "true", 1); menu->SetMenuItemChecked(mi_cli, 1); clientdetailt->Show(); } } else if (mi == mi_graphsig) { opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHSIG"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHSIG", "false", 1); menu->SetMenuItemChecked(mi_graphsig, 0); siggraph->Hide(); } else { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHSIG", "true", 1); menu->SetMenuItemChecked(mi_graphsig, 1); siggraph->Show(); } } else if (mi == mi_graphpacket) { opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHPACKET"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHPACKET", "false", 1); menu->SetMenuItemChecked(mi_graphpacket, 0); packetgraph->Hide(); } else { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHPACKET", "true", 1); menu->SetMenuItemChecked(mi_graphpacket, 1); packetgraph->Show(); } } else if (mi == mi_graphretry) { opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHRETRY"); if (opt == "" || opt == "true") { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHRETRY", "false", 1); menu->SetMenuItemChecked(mi_graphretry, 0); retrygraph->Hide(); } else { kpinterface->prefs->SetOpt("CLIDETAILS_SHOWGRAPHRETRY", "true", 1); menu->SetMenuItemChecked(mi_graphretry, 1); retrygraph->Show(); } } else if (mi == -1) { opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWCLI"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_cli, 1); clientdetailt->Show(); } else { menu->SetMenuItemChecked(mi_cli, 0); clientdetailt->Hide(); } opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHSIG"); if (opt == "true") { menu->SetMenuItemChecked(mi_graphsig, 1); siggraph->Show(); } else { menu->SetMenuItemChecked(mi_graphsig, 0); siggraph->Hide(); } opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHPACKET"); if (opt == "" || opt == "true") { menu->SetMenuItemChecked(mi_graphpacket, 1); packetgraph->Show(); } else { menu->SetMenuItemChecked(mi_graphpacket, 0); packetgraph->Hide(); } opt = kpinterface->prefs->FetchOpt("CLIDETAILS_SHOWGRAPHRETRY"); if (opt == "true") { menu->SetMenuItemChecked(mi_graphretry, 1); retrygraph->Show(); } else { menu->SetMenuItemChecked(mi_graphretry, 0); retrygraph->Hide(); } } } int AlertDetailsButtonCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AlertDetails_Panel *) aux)->ButtonAction(component); return 1; } int AlertDetailsMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_AlertDetails_Panel *) aux)->MenuAction(status); return 1; } class KisAlert_Sort_Time { public: inline bool operator()(KisPanelInterface::knc_alert *x, KisPanelInterface::knc_alert *y) const { if (x->tv.tv_sec < y->tv.tv_sec || (x->tv.tv_sec == y->tv.tv_sec && x->tv.tv_usec < y->tv.tv_usec)) return 1; return 0; } }; class KisAlert_Sort_TimeInv { public: inline bool operator()(KisPanelInterface::knc_alert *x, KisPanelInterface::knc_alert *y) const { if (x->tv.tv_sec < y->tv.tv_sec || (x->tv.tv_sec == y->tv.tv_sec && x->tv.tv_usec < y->tv.tv_usec)) return 0; return 1; } }; class KisAlert_Sort_Type { public: inline bool operator()(KisPanelInterface::knc_alert *x, KisPanelInterface::knc_alert *y) const { return x->alertname < y->alertname; } }; class KisAlert_Sort_Bssid { public: inline bool operator()(KisPanelInterface::knc_alert *x, KisPanelInterface::knc_alert *y) const { return x->bssid < y->bssid; } }; Kis_AlertDetails_Panel::Kis_AlertDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { last_alert = NULL; last_selected = NULL; last_sort = 0; menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, AlertDetailsMenuCB, this); mn_alert = menu->AddMenu("Alert", 0); mi_close = menu->AddMenuItem("Close window", mn_alert, 'w'); mn_sort = menu->AddMenu("Sort", 0); mi_latest = menu->AddMenuItem("Latest", mn_sort, 'l'); mi_time = menu->AddMenuItem("Time", mn_sort, 't'); mi_type = menu->AddMenuItem("Type", mn_sort, 'T'); mi_bssid = menu->AddMenuItem("BSSID", mn_sort, 'b'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); alertlist = new Kis_Scrollable_Table(globalreg, this); alertlist->SetHighlightSelected(1); alertlist->SetLockScrollTop(1); alertlist->SetDrawTitles(0); AddComponentVec(alertlist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); vector titles; Kis_Scrollable_Table::title_data t; t.width = 8; t.title = "time"; t.alignment = 2; titles.push_back(t); t.width = 10; t.title = "header"; t.alignment = 0; titles.push_back(t); t.width = 0; t.title = "text"; t.alignment = 0; titles.push_back(t); alertlist->AddTitles(titles); alertlist->Show(); alertdetails = new Kis_Scrollable_Table(globalreg, this); alertdetails->SetHighlightSelected(0); alertdetails->SetLockScrollTop(1); alertdetails->SetDrawTitles(0); alertdetails->SetPreferredSize(0, 6); AddComponentVec(alertdetails, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); titles.clear(); t.width = 12; t.title = "field"; t.alignment = 2; titles.push_back(t); t.width = 0; t.title = "text"; t.alignment = 0; titles.push_back(t); alertdetails->AddTitles(titles); alertdetails->SetPreferredSize(0, 6); alertdetails->Show(); SetTitle(""); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(alertlist, 1, 0); vbox->Pack_End(alertdetails, 0, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); main_component = vbox; SetActiveComponent(alertlist); UpdateSortPrefs(1); UpdateSortMenu(-1); Position(WIN_CENTER(LINES, COLS)); } Kis_AlertDetails_Panel::~Kis_AlertDetails_Panel() { } void Kis_AlertDetails_Panel::DrawPanel() { vector *raw_alerts = kpinterface->FetchAlertVec(); int k = 0; vector td; td.push_back(""); td.push_back(""); td.push_back(""); // No custom drawing if we have no alerts if (raw_alerts->size() == 0) { sorted_alerts.clear(); alertdetails->Clear(); alertlist->Clear(); td[0] = ""; td[1] = ""; td[2] = "No alerts"; alertlist->ReplaceRow(k++, td); Kis_Panel::DrawPanel(); return; } // If we've changed the list if ((*raw_alerts)[raw_alerts->size() - 1] != last_alert) { sorted_alerts = *raw_alerts; switch (sort_mode) { case alertsort_time: stable_sort(sorted_alerts.begin(), sorted_alerts.end(), KisAlert_Sort_Time()); break; case alertsort_latest: stable_sort(sorted_alerts.begin(), sorted_alerts.end(), KisAlert_Sort_TimeInv()); break; case alertsort_type: stable_sort(sorted_alerts.begin(), sorted_alerts.end(), KisAlert_Sort_Type()); break; case alertsort_bssid: stable_sort(sorted_alerts.begin(), sorted_alerts.end(), KisAlert_Sort_Bssid()); break; } for (unsigned int x = 0; x < sorted_alerts.size(); x++) { td[0] = string(ctime((const time_t *) &(sorted_alerts[x]->tv.tv_sec))).substr(11, 8); td[1] = sorted_alerts[x]->alertname; td[2] = sorted_alerts[x]->text; alertlist->ReplaceRow(k++, td); } } td.clear(); td.push_back(""); td.push_back(""); k = 0; // Update the details for the selected alert if we've changed if (alertlist->GetSelected() >= 0 && alertlist->GetSelected() < (int) sorted_alerts.size()) { if (sorted_alerts[alertlist->GetSelected()] != last_selected) { last_selected = sorted_alerts[alertlist->GetSelected()]; alertdetails->Clear(); td[0] = "Time:"; td[1] = string(ctime((const time_t *) &(last_selected->tv.tv_sec))).substr(4, 15); alertdetails->ReplaceRow(k++, td); td[0] = "Alert:"; td[1] = last_selected->alertname; alertdetails->ReplaceRow(k++, td); td[0] = "BSSID:"; td[1] = last_selected->bssid.Mac2String(); alertdetails->ReplaceRow(k++, td); td[0] = "Source:"; td[1] = last_selected->source.Mac2String(); alertdetails->ReplaceRow(k++, td); td[0] = "Dest:"; td[1] = last_selected->dest.Mac2String(); alertdetails->ReplaceRow(k++, td); td[0] = "Channel:"; td[1] = IntToString(last_selected->channel); alertdetails->ReplaceRow(k++, td); td[0] = "Text:"; td[1] = last_selected->text; alertdetails->ReplaceRow(k++, td); } } else { alertdetails->Clear(); td[0] = ""; td[1] = "No alert selected"; alertdetails->ReplaceRow(k++, td); } Kis_Panel::DrawPanel(); } void Kis_AlertDetails_Panel::ButtonAction(Kis_Panel_Component *in_button) { } void Kis_AlertDetails_Panel::MenuAction(int opt) { // Menu processed an event, do something with it if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } else if (opt == mi_time) { kpinterface->prefs->SetOpt("ALERTLIST_SORT", "time", time(0)); } else if (opt == mi_latest) { kpinterface->prefs->SetOpt("ALERTLIST_SORT", "latest", time(0)); } else if (opt == mi_type) { kpinterface->prefs->SetOpt("ALERTLIST_SORT", "type", time(0)); } else if (opt == mi_bssid) { kpinterface->prefs->SetOpt("ALERTLIST_SORT", "bssid", time(0)); } if (opt == mi_time || opt == mi_latest || opt == mi_type || opt == mi_bssid) { UpdateSortPrefs(0); UpdateSortMenu(opt); } } void Kis_AlertDetails_Panel::UpdateSortMenu(int mi) { menu->SetMenuItemChecked(mi_time, sort_mode == alertsort_time); menu->SetMenuItemChecked(mi_latest, sort_mode == alertsort_latest); menu->SetMenuItemChecked(mi_type, sort_mode == alertsort_type); menu->SetMenuItemChecked(mi_bssid, sort_mode == alertsort_bssid); } int Kis_AlertDetails_Panel::UpdateSortPrefs(int always) { string sort; if ((sort = kpinterface->prefs->FetchOpt("ALERTLIST_SORT")) == "") { sort = "latest"; kpinterface->prefs->SetOpt("ALERTLIST_SORT", sort, time(0)); } if (kpinterface->prefs->FetchOptDirty("ALERTLIST_SORT") < last_sort && always == 0) return 0; last_sort = kpinterface->prefs->FetchOptDirty("ALERTLIST_SORT"); sort = StrLower(sort); if (sort == "latest") sort_mode = alertsort_latest; else if (sort == "time") sort_mode = alertsort_time; else if (sort == "type") sort_mode = alertsort_type; else if (sort == "bssid") sort_mode = alertsort_bssid; else sort_mode = alertsort_latest; return 1; } int RegDetailsMenuCB(COMPONENT_CALLBACK_PARMS) { ((Kis_RegDetails_Panel *) aux)->MenuAction(status); return 1; } Kis_RegDetails_Panel::Kis_RegDetails_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) : Kis_Panel(in_globalreg, in_intf) { menu = new Kis_Menu(globalreg, this); menu->SetCallback(COMPONENT_CBTYPE_ACTIVATED, RegDetailsMenuCB, this); mn_regd = menu->AddMenu("Reg", 0); mi_close = menu->AddMenuItem("Close window", mn_regd, 'w'); menu->Show(); AddComponentVec(menu, KIS_PANEL_COMP_EVT); reglist = new Kis_Scrollable_Table(globalreg, this); reglist->SetHighlightSelected(1); reglist->SetLockScrollTop(1); reglist->SetDrawTitles(1); AddComponentVec(reglist, (KIS_PANEL_COMP_DRAW | KIS_PANEL_COMP_EVT | KIS_PANEL_COMP_TAB)); vector titles; Kis_Scrollable_Table::title_data t; t.width = 8; t.title = "Cty"; t.alignment = 0; titles.push_back(t); t.width = 4; t.title = "#Net"; t.alignment = 3; titles.push_back(t); t.width = 0; t.title = "Channels"; t.alignment = 0; titles.push_back(t); netlist = new Kis_Netlist(globalreg, this); netlist->Show(); netlist->SetPreferredSize(0, 10); AddComponentVec(netlist, KIS_PANEL_COMP_TAB | KIS_PANEL_COMP_EVT); text = new Kis_Free_Text(globalreg, this); text->Show(); SetTitle(""); vbox = new Kis_Panel_Packbox(globalreg, this); vbox->SetPackV(); vbox->SetHomogenous(0); vbox->SetSpacing(0); vbox->Show(); vbox->Pack_End(reglist, 1, 0); vbox->Pack_End(netlist, 0, 0); vbox->Pack_End(text, 0, 0); AddComponentVec(vbox, KIS_PANEL_COMP_DRAW); main_component = vbox; SetActiveComponent(reglist); main_netlist = kpinterface->FetchMainPanel()->FetchDisplayNetlist(); Position(WIN_CENTER(LINES, COLS)); } Kis_RegDetails_Panel::~Kis_RegDetails_Panel() { delete netlist; } void Kis_RegDetails_Panel::DrawPanel() { // Kind of ugly but it's a specialty panel if (main_netlist == NULL) return; // vector *display_vctor = main_netlist->FetchDisplayVector(); } void Kis_RegDetails_Panel::MenuAction(int opt) { if (opt == mi_close) { globalreg->panel_interface->KillPanel(this); return; } } #endif kismet-2013-03-R1b/packetsourcetracker.h0000664000175000017500000002637712124602454017707 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCETRACKER_H__ #define __PACKETSOURCETRACKER_H__ #include "config.h" #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "timetracker.h" #include "packetsource.h" #include "pollable.h" #include "ipc_remote.h" #include "kis_pktproto.h" /* * Core of the packet tracking subsystem * * Packet source types are registered by passing a "weak" variant of the class * (instantiated packetsource without bindings to the actual source or polling * functions) which provides the necessary info for deriving "strong" packet sources * which are bound to interfaces and operate normally. * * Initial config parsing (sources and channels) is done by the user system. * * Root packet sources are handled by a spawned root binary which passes packets and * state back via IPC frames. Root sources must be communicated to the IPC system, * and state changes pushed across. * * All packetsource ops should be non-fatal, and return error conditions. * PST will decide if the operation is fatal (config file source type doesn't exist, * etc) or non-fatal (dynamically added sources get a pass for being broken) * */ // Maximum number of consecutive errors setting a channel before we consider this // to be a failure condition #define MAX_CONSEC_CHAN_ERR 5 // Channel record struct pst_channel { // Control options; phy/source dependent, ex. HT20, HT40+/- int control_flags; // are we a range int range; union { // Frequency/dwell pair struct { unsigned int channel; unsigned int dwell; } chan_t; // Range defintion plus local counter struct { unsigned int start; unsigned int end; unsigned int width; unsigned int iter; } range_t; } u; }; struct pst_channellist { // Channel list ID (for ipc) uint16_t channel_id; string name; int auto_generated; vector channel_vec; }; struct pst_protosource { string type; KisPacketSource *weak_source; string default_channelset; int require_root; }; // Packetsource tracking record struct pst_packetsource { // Source ID for IPC uint16_t source_id; // We need this if we don't have a strong source string interface; // Should we not go over IPC? Most things should. int local_only; // Source definition string sourceline; // Prototype we were built from pst_protosource *proto_source; // Local strong packet source (even for remote sources, we need a process-local // strong source which has interpreted all the options for us KisPacketSource *strong_source; // Channel list we've assigned uint16_t channel_list; // Pointer to channel list pst_channellist *channel_ptr; // Specific channel if we're not hopping uint16_t channel; // Per-source hop, dwell, and rate int channel_hop; int channel_dwell; int channel_rate; int channel_split; int dwell_timer; int rate_timer; // Position in list, initialized by source splitting int channel_position; int range_position; // Number of consec channel set errors int consec_channel_err; struct timeval tm_hop_start; struct timeval tm_hop_time; // Are we in error state? int error; // Do we re-open on error? int reopen; // How many zero-polls have we had in a row? int zeropoll; // Do we have a PST-tracker level warning? string warning; }; // Callback for actions on sources. Gives the source and action type, flags, // and an arbitrary pointer. #define SOURCEACT_PARMS GlobalRegistry *globalreg, pst_packetsource *src, \ int action, int flags, void *auxptr typedef void (*SourceActCallback)(SOURCEACT_PARMS); // Various actions. Adding, deleting, hop setting, vector setting #define SOURCEACT_ADDSOURCE 0 #define SOURCEACT_DELSOURCE 1 #define SOURCEACT_HOPENABLE 2 #define SOURCEACT_HOPDISABLE 3 #define SOURCEACT_CHVECTOR 4 #define SOURCEACT_CHHOPDWELL 5 class Packetsourcetracker : public Pollable { public: Packetsourcetracker(GlobalRegistry *in_globalreg); virtual ~Packetsourcetracker(); // Bind an IPC helper (as parent or child) void RegisterIPC(IPCRemote *in_ipc, int in_as_ipc); // Help static void Usage(char *name); // Pollable system handlers virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set &in_rset, fd_set& in_wset); // Register a packet source type (pass a weak source) int RegisterPacketSource(KisPacketSource *in_weak); // Register a packet prototype (called by source registration) int RegisterPacketProto(string in_type, KisPacketSource *in_weak, string in_defaultchan, int in_root); // Add a packet source, get back a reference ID // ncsource=interface,[opt=val]+ // ie ncsource=wlan0,name=foobar,type=iwl4965 // // The packet source will be sent immediately upon parsing to the IPC process. // If a strong source is passed (instead of NULL) the type matching will be // bypassed and the strong source assigned. This should only be used for // dynamic sources added locally (such as the drone code) int AddPacketSource(string in_source, KisPacketSource *in_strong, uint16_t *source_id); int RemovePacketSource(pst_packetsource *in_source); // Add a run-time packet source & wrap the internal AddPacketsource to return // an error code instead of an internal sourcenum. The optional strong source will // be used instead of resolving the source from the list of source types, and // the source will be activated (locally if a strong source is passed, remotely // if not) int AddLivePacketSource(string in_source, KisPacketSource *in_strong); // Manipulate sources based on strong pointers int RemoveLivePacketSource(KisPacketSource *in_strong); pst_packetsource *FindLivePacketSource(KisPacketSource *in_strong); pst_packetsource *FindLivePacketSourceUUID(uuid in_uuid); KisPacketSource *FindKisPacketSourceUUID(uuid in_uuid); // Find source by name pst_packetsource *FindLivePacketSourceName(string name); // Actually load the configuration int LoadConfiguration(); // Create IPC-local data from IPC setup frames int IpcAddChannelList(ipc_source_add_chanlist *in_ipc); int IpcAddPacketsource(ipc_source_add *in_ipc); int IpcChannelSet(ipc_source_chanset *in_ipc); int IpcSourceReport(ipc_source_report *in_ipc); int IpcSourceRun(ipc_source_run *in_ipc); int IpcSourceRemove(ipc_source_remove *in_ipc); int IpcPacket(ipc_source_packet *in_ipc); int IpcChannelReport(ipc_source_chanreport *in_ipc); int StartSource(uint16_t in_source_id); int StopSource(uint16_t in_source_id); // Add a callback for notifying external elements when a packet source is added int RegisterSourceActCallback(SourceActCallback in_cb, void *in_aux); int RemoveSourceActCallback(SourceActCallback in_cb); // Change a source between hopping and non-hopping (within the same channel set) int SetSourceHopping(uuid in_uuid, int in_hopping, uint16_t in_channel); // Change a source to a newly defined channel list int SetSourceNewChannellist(uuid in_uuid, string in_channellist); // Change a source hop/dwell settings int SetSourceHopDwell(uuid in_uuid, int in_rate, int in_dwell); // Low-level hook to dig into all the packet sources, for stuff like Drone // to function properly vector *FetchSourceVec() { return &packetsource_vec; } pst_channellist *FetchSourceChannelList(pst_packetsource *in_src); void ChannelTimer(); void OpenTimer(); // Packet chain to IPC / DLT demangle void ChainHandler(kis_packet *in_pack); typedef struct { SourceActCallback cb; void *auxdata; } sourceactcb_rec; // Network protocol stuff void BlitSources(int in_fd); void BlitProtoSources(int in_fd); // Network commands int cmd_ADDSOURCE(int, KisNetFramework *, char *, string, vector *); int cmd_DELSOURCE(int, KisNetFramework *, char *, string, vector *); int cmd_RESTARTSOURCE(int, KisNetFramework *, char *, string, vector *); int cmd_HOPSOURCE(int, KisNetFramework *, char *, string, vector *); int cmd_CHANLIST(int, KisNetFramework *, char *, string, vector *); // Fetch and clear the channel time map map *FetchChannelTickMap() { return &channel_tick_map; } void ClearChannelTickMap() { channel_tick_map.clear(); } // Add a channel list, get back a reference ID (ie, for IPC) // channels=name,chan[:dwell]+ // ie channels=dot11g,1:5,2,3,4,5,6:5,7,8,9,10,11:5 // // The channel list will be sent immediately upon parsing to the IPC process uint16_t AddChannelList(string in_chanlist); // Generate a channel list from a vector (ie hw channel from the protosource); // Compare with other autogenerated channel lists and figure out if we have // an overlap and return the overlapped sources if we do uint16_t GenChannelList(vector in_channellist); protected: void SendIPCSourceAdd(pst_packetsource *in_source); void SendIPCChannellist(pst_channellist *in_list); void SendIPCReport(pst_packetsource *in_source); void SendIPCStart(pst_packetsource *in_source); void SendIPCStop(pst_packetsource *in_source); void SendIPCChanset(pst_packetsource *in_source); void SendIPCRemove(pst_packetsource *in_source); void SendIPCPacket(kis_packet *in_packet, kis_datachunk *in_linkchunk); void SendIPCChanreport(); GlobalRegistry *globalreg; IPCRemote *rootipc; int source_ipc_id, channellist_ipc_id, channel_ipc_id, report_ipc_id, run_ipc_id, remove_ipc_id, sync_ipc_id, packet_ipc_id, chanreport_ipc_id, stop_ipc_id; int cmd_addsource_id, cmd_delsource_id, cmd_restartsource_id, cmd_hopsource_id, cmd_channellist_id; int running_as_ipc; uint16_t next_source_id; uint16_t next_channel_id; // Values before they are overridden by the local hop int default_channel_rate; int default_channel_dwell; int channel_time_id, proto_source_time_id, open_time_id; int source_protoref; int timer_counter; // List of prototype source, we don't need a map (saves on ram and binary, // to some extent) vector protosource_vec; pst_protosource *broken_proto; // Map of ID to strong packet sources we've made map packetsource_map; // Because iterating maps is super slow vector packetsource_vec; vector named_vec; // Map of channel IDs map channellist_map; // Callbacks for adding a source vector cb_vec; // Number of ticks we've spent per channel in the past second map channel_tick_map; // Preferred channels vector preferred_channels; }; #endif kismet-2013-03-R1b/kis_panel_widgets.cc0000664000175000017500000025137712124602454017474 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include "kis_panel_widgets.h" #include "kis_panel_frontend.h" #include "timetracker.h" #include "messagebus.h" #define WIN_CENTER(h, w) (LINES / 2) - ((h) / 2), (COLS / 2) - ((w) / 2), (h), (w) unsigned int Kis_Panel_Specialtext::Strlen(string str) { int npos = 0; int escape = 0; for (unsigned int pos = 0; pos < str.size(); pos++) { if (str[pos] == '\004') { escape = 1; continue; } if (escape) { escape = 0; if (str[pos] == 'C') { // Color escape code: // \004Ccolorpref;text // Catch malforms at the end if (pos >= str.length()) { continue; } size_t colorend = str.find(";", pos + 1); if (colorend == string::npos) continue; pos = colorend; } continue; } npos++; } return npos; } void Kis_Panel_Specialtext::Mvwaddnstr(WINDOW *win, int y, int x, string str, int n, Kis_Panel *panel, int colorpair) { int npos = 0; int escape = 0; for (unsigned int pos = 0; pos < str.size(); pos++) { if (str[pos] == '\004') { escape = 1; continue; } // Handle the attributes if (escape) { if (str[pos] == 'u') { wattron(win, WA_UNDERLINE); } else if (str[pos] == 'U') { wattroff(win, WA_UNDERLINE); } else if (str[pos] == 's') { wattron(win, WA_STANDOUT); } else if (str[pos] == 'S') { wattroff(win, WA_STANDOUT); } else if (str[pos] == 'r') { wattron(win, WA_REVERSE); } else if (str[pos] == 'R') { wattroff(win, WA_REVERSE); } else if (str[pos] == 'b') { if ((colorpair & A_BOLD) == 0) wattron(win, WA_BOLD); } else if (str[pos] == 'B') { if ((colorpair & A_BOLD) == 0) wattroff(win, WA_BOLD); } else if (str[pos] == 'C') { // Color escape code: // \004Ccolorpref;text // Catch malforms at the end if (pos >= str.length()) { continue; } size_t colorend = str.find(";", pos + 1); if (colorend != string::npos) { string cpref = str.substr(pos + 1, colorend - pos - 1); int c = 0; panel->ColorFromPref(c, cpref); pos = colorend; if (c > 0) wattrset(win, c); } } else { // fprintf(stderr, "invalid escape '%c'\n", str[pos]); // Backfill the unescaped data escape = 0; if (npos <= n) { mvwaddch(win, y, x + npos, '\\'); npos++; } if (npos <= n) { mvwaddch(win, y, x + npos, str[npos]); npos++; } } escape = 0; continue; } // Otherwise write the character, if we can. We DON'T abort here, // because we need to process to the end of the string to turn off // any attributes that were on if (npos <= n) { mvwaddch(win, y, x + npos, str[pos]); npos++; continue; } } } Kis_Panel_Color::Kis_Panel_Color() { // nextindex = COLORS + 1; nextindex = 1; } int Kis_Panel_Color::AddColor(string color, string pref) { map::iterator cimi; short nums[2] = {0, 0}; int bold = 0; int pair; if ((cimi = color_index_map.find(StrLower(color))) != color_index_map.end()) { return cimi->second.colorindex; } if (nextindex == COLOR_PAIRS - 1) { // fprintf(stderr, "debug - too many color pairs\n"); return COLOR_PAIR(0); } vector colorpair = StrTokenize(color, ","); if (colorpair.size() < 1) colorpair.push_back("white"); if (colorpair.size() < 2) colorpair.push_back("black"); colorpair[0] = StrLower(colorpair[0]); colorpair[1] = StrLower(colorpair[1]); for (unsigned int x = 0; x < 2; x++) { string clr = colorpair[x]; if (clr == "grey" || clr == "gray") clr = "hi-black"; // First, find if theres a hi- if (clr.substr(0, 3) == "hi-") { bold = 1; clr = clr.substr(3, clr.length() - 3); } // Then match all the colors if (clr == "default") nums[x] = -1; else if (clr == "black") nums[x] = COLOR_BLACK; else if (clr == "red") nums[x] = COLOR_RED; else if (clr == "green") nums[x] = COLOR_GREEN; else if (clr == "yellow") nums[x] = COLOR_YELLOW; else if (clr == "blue") nums[x] = COLOR_BLUE; else if (clr == "magenta") nums[x] = COLOR_MAGENTA; else if (clr == "cyan") nums[x] = COLOR_CYAN; else if (clr == "white") nums[x] = COLOR_WHITE; } // fprintf(stderr, "debug - color init_pair %d vals %d, %d\n", nextindex, nums[0], nums[1]); init_pair(nextindex, nums[0], nums[1]); pair = COLOR_PAIR(nextindex); if (bold) { pair |= A_BOLD; } color_rec cr; cr.pref = pref; cr.color[0] = colorpair[0]; cr.color[1] = colorpair[1]; cr.colorindex = pair; color_index_map[StrLower(color)] = cr; nextindex++; return pair; } void Kis_Panel_Color::RemapAllColors(string oldcolor, string newcolor, ConfigFile *conf) { map::iterator cri; string o = StrLower(oldcolor), n = StrLower(newcolor); for (cri = color_index_map.begin(); cri != color_index_map.end(); ++cri) { int s = 0; if (cri->second.pref == "") continue; if (cri->second.color[0] == o) { cri->second.color[0] = n; s = 1; } if (cri->second.color[1] == o) { cri->second.color[1] = n; s = 1; } if (s) conf->SetOpt(cri->second.pref, cri->second.color[0] + string(",") + cri->second.color[1], time(0)); } } int panelint_draw_timer(TIMEEVENT_PARMS) { return ((PanelInterface *) parm)->DrawInterface(); } // Pollable panel interface driver PanelInterface::PanelInterface() { fprintf(stderr, "FATAL OOPS: PanelInterface() w/ no globalreg\n"); exit(1); } PanelInterface::PanelInterface(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; // Init curses initscr(); raw(); cbreak(); noecho(); keypad(stdscr, 1); meta(stdscr, 1); mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); start_color(); use_default_colors(); draweventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC / 2, NULL, 1, &panelint_draw_timer, (void *) this); globalreg->RegisterPollableSubsys(this); getmaxyx(stdscr, hsize, vsize); }; PanelInterface::~PanelInterface() { for (unsigned int x = 0; x < live_panels.size(); x++) delete live_panels[x]; globalreg->timetracker->RemoveTimer(draweventid); globalreg->RemovePollableSubsys(this); erase(); if (isendwin() == 0) endwin(); } int PanelInterface::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { if (globalreg->spindown) return in_max_fd; if (live_panels.size() == 0) return in_max_fd; // add stdin to the listen set FD_SET(fileno(stdin), out_rset); if (in_max_fd < fileno(stdin)) return fileno(stdin); return in_max_fd; } int PanelInterface::Poll(fd_set& in_rset, fd_set& in_wset) { if (live_panels.size() == 0) return 0; if (FD_ISSET(fileno(stdin), &in_rset)) { // Poll via the top of the stack int ret; ret = live_panels[live_panels.size() - 1]->Poll(); DrawInterface(); if (ret < 0) globalreg->fatal_condition = 1; return ret; } return 0; } void PanelInterface::ResizeInterface() { int nh, nv; endwin(); refresh(); getmaxyx(stdscr, nh, nv); if (hsize == nh && vsize == nv) { return; } for (unsigned int x = 0; x < live_panels.size(); x++) { // If it's full screen, keep it full screen, otherwise // re-center it if (live_panels[x]->FetchSzy() == hsize && live_panels[x]->FetchSzx() == vsize) { live_panels[x]->Position(0, 0, nh, nv); } else { int rsy = live_panels[x]->FetchSzy(), rsx = live_panels[x]->FetchSzx(); if (rsy > nh) rsy = nh; if (rsx > nv) rsx = nv; live_panels[x]->Position(WIN_CENTER(rsy, rsx)); } } hsize = nh; vsize = nv; } int PanelInterface::DrawInterface() { // Draw all the panels for (unsigned int x = 0; x < live_panels.size(); x++) { live_panels[x]->DrawPanel(); } // Call the update update_panels(); doupdate(); // Delete dead panels from before for (unsigned int x = 0; x < dead_panels.size(); x++) { delete(dead_panels[x]); } dead_panels.clear(); return 1; } void PanelInterface::AddPanel(Kis_Panel *in_panel) { live_panels.push_back(in_panel); } void PanelInterface::KillPanel(Kis_Panel *in_panel) { for (unsigned int x = 0; x < live_panels.size(); x++) { if (live_panels[x] == in_panel) { dead_panels.push_back(in_panel); live_panels.erase(live_panels.begin() + x); } } } Kis_Panel_Component::Kis_Panel_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) { globalreg = in_globalreg; parent_panel = in_panel; window = in_panel->FetchDrawWindow(); visible = 0; active = 0; sx = sy = ex = ey = lx = ly = 0; px = py = 0; mx = my = 0; layout_dirty = 0; cb_switch = cb_activate = NULL; color_active = color_inactive = 0; color_active_pref = "panel_text_color"; color_inactive_pref = "panel_textdis_color"; name = "GENERIC_WIDGET"; } void Kis_Panel_Component::SetCallback(int cbtype, int (*cb)(COMPONENT_CALLBACK_PARMS), void *aux) { switch (cbtype) { case COMPONENT_CBTYPE_SWITCH: cb_switch = cb; cb_switch_aux = aux; break; case COMPONENT_CBTYPE_ACTIVATED: cb_activate = cb; cb_activate_aux = aux; break; } } void Kis_Panel_Component::ClearCallback(int cbtype) { switch (cbtype) { case COMPONENT_CBTYPE_SWITCH: cb_switch = NULL; break; case COMPONENT_CBTYPE_ACTIVATED: cb_activate = NULL; break; } } Kis_Panel_Packbox::Kis_Panel_Packbox(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { homogenous = 0; packing = 0; spacing = 0; center = 0; name = "GENERIC_PACKBOX"; } Kis_Panel_Packbox::~Kis_Panel_Packbox() { // Nothing to do really } int Kis_Panel_Packbox::GetVisible() { if (visible == 0) return 0; int any_vis = 0; for (list::iterator x = packed_items.begin(); x != packed_items.end(); ++x) { if ((*x).widget->GetVisible()) { any_vis = 1; break; } } if (any_vis) return 1; return 0; } void Kis_Panel_Packbox::Pack_Start(Kis_Panel_Component *in_widget, int in_fill, int in_padding) { packbox_details det; det.widget = in_widget; det.fill = in_fill; det.padding = in_padding; packed_items.push_front(det); layout_dirty = 1; } void Kis_Panel_Packbox::Pack_End(Kis_Panel_Component *in_widget, int in_fill, int in_padding) { packbox_details det; det.widget = in_widget; det.fill = in_fill; det.padding = in_padding; packed_items.push_back(det); layout_dirty = 1; } void Kis_Panel_Packbox::Pack_Before_Named(string in_name, Kis_Panel_Component *in_widget, int in_fill, int in_padding) { list::iterator i; packbox_details det; det.widget = in_widget; det.fill = in_fill; det.padding = in_padding; layout_dirty = 1; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget->GetName() == in_name) { packed_items.insert(i, det); return; } } packed_items.push_back(det); return; } void Kis_Panel_Packbox::Pack_After_Named(string in_name, Kis_Panel_Component *in_widget, int in_fill, int in_padding) { list::iterator i; packbox_details det; det.widget = in_widget; det.fill = in_fill; det.padding = in_padding; layout_dirty = 1; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget->GetName() == in_name) { packed_items.insert(++i, det); return; } } packed_items.push_back(det); return; } void Kis_Panel_Packbox::Pack_Remove(Kis_Panel_Component *in_widget) { list::iterator i; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget == in_widget) { packed_items.erase(i); layout_dirty = 1; return; } } } void Kis_Panel_Packbox::Pack_Widgets() { int size, psize, msize, pos; list::iterator i; if (visible == 0) return; // Get the packing direction if (packing == 0) { size = lx; } else { size = ly; } // If we're homogenous, we divide by the # of widgets, find out if we're too // small for any of them, and decrease until we can fit them if (homogenous) { int ndivs = packed_items.size(); int perbox = 0; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget->GetVisible() == 0) { ndivs--; continue; } } for (i = packed_items.begin(); i != packed_items.end(); ++i) { int wmsize; if ((*i).widget->GetVisible() == 0) { continue; } perbox = (int) ((float) (size - (spacing * (ndivs - 1))) / ndivs); if (packing == 0) { wmsize = (*i).widget->GetMinX(); } else { wmsize = (*i).widget->GetMinY(); } // If someone can't fit, decrease the number of divisions until we // can, and we just don't draw those widgets. Yeah, it sucks, // don't over-pack a small frame if (wmsize > perbox) { // If we simply can't fix the widget in, period, then bail on // drawing. if (ndivs <= 1) { // fprintf(stderr, "we couldn't find, wah\n"); return; } ndivs -= 1; i = packed_items.begin(); continue; } } i = packed_items.begin(); for (int x = 0; x < ndivs && i != packed_items.end(); x++, ++i) { if ((*i).widget->GetVisible() == 0) { x--; continue; } // Set the position of each widget int ww = perbox - ((*i).padding * 2); int co = 0; // Get the preferred size (or best we can do) OR the fill int psize = 0, op = 0; if ((*i).fill == 0) { if (packing == 0) { psize = (*i).widget->GetPrefX() + ((*i).padding * 2); op = ly; } else { psize = (*i).widget->GetPrefY() + ((*i).padding * 2); op = lx; } if (psize > ww) psize = ww; } else { psize = ww; } if (center && psize != ww) { co = (ww - psize) / 2; } if (packing == 0) { (*i).widget->SetPosition( sx + (perbox * x) + (*i).padding + co, sy, sx + (perbox * x) + (*i).padding + co + psize, sy + op); } else { (*i).widget->SetPosition( sx, sy + (perbox * x) + (*i).padding + co, sx + op, sy + (perbox * x) + (*i).padding + co + psize); } } return; // Done w/ homogenous spacing } // Non-homogenous spacing // Pass 1: Can we fit everyone who has a preferred size in? If we can, then // we can just start expanding them (or just plain draw them as is if we // don't have any filler). Calculate preferred and minimum sizes simultaneously // to save another iteration. psize = 0; msize = 0; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget->GetVisible() == 0) continue; if (packing == 0) { psize += (*i).widget->GetPrefX() + ((*i).padding * 2); msize += (*i).widget->GetMinX() + ((*i).padding * 2); } else { psize += (*i).widget->GetPrefY() + ((*i).padding * 2); msize += (*i).widget->GetMinY() + ((*i).padding * 2); } } // If we can't fit the preferred, can we fit the minimum? if (psize > size) { // fprintf(stderr, "debug - %p can't fit preferred\n", this); if (msize <= size) { // fprintf(stderr, "debug - %p can fit in size\n", this); pos = 0; // Fit them via minsize, giving them space from the free // bucket so long as we have it int bucket = size - msize; // fprintf(stderr, "debug - %p has bucket %d for items, min %d\n", this, bucket, msize); i = packed_items.begin(); for (int x = 0; i != packed_items.end(); ++i, x++) { if ((*i).widget->GetVisible() == 0) continue; int mp, pp, op; if (packing == 0) { mp = (*i).widget->GetMinX(); pp = (*i).widget->GetPrefX(); /* op = (*i).widget->GetPrefY(); if (op > ly || op == 0) op = ly; */ op = ly; } else { mp = (*i).widget->GetMinY(); pp = (*i).widget->GetPrefY(); /* op = (*i).widget->GetPrefX(); if (op > lx || op == 0) op = lx; */ op = lx; } int ww; ww = mp + ((*i).padding * 2); // fprintf(stderr, "debug - %p item %d gets %d\n", this, x, ww); if (bucket > 0 && mp < pp) { int delta = pp - mp; if (delta > bucket) delta = bucket; // fprintf(stderr, "debug - %p gave %d to item %d min %d wanted %d was %d now %d\n", this, delta, x, mp, pp - mp, ww, ww+delta); bucket -= delta; ww += delta; } if (packing == 0) { (*i).widget->SetPosition( sx + (spacing * x) + pos, sy, sx + (spacing * x) + pos + ww, sy + op); } else { (*i).widget->SetPosition( sx, sy + (spacing * x) + pos, sx + op, sy + (spacing * x) + pos + ww); } pos += ww; } } return; } /* Otherwise, we can more than fit our widgets... * So the first order of business, find out how many are set to expand, * and how much slush space we have to give them */ // fprintf(stderr, "debug - %p we can fit all preferred\n", this); int bucket = 0; int num_fill = 0; for (i = packed_items.begin(); i != packed_items.end(); ++i) { int pp; if ((*i).widget->GetVisible() == 0) continue; if (packing == 0) { pp = (*i).widget->GetPrefX(); } else { pp = (*i).widget->GetPrefY(); } /* Add up all the ones which aren't expanding to let us know * how much we can give to the ones we can give more to */ if ((*i).fill == 0) { bucket += pp; } else { num_fill++; } } // Reclaim our variable - our free bucket is the remainder of unclaimed // stuff bucket = size - bucket - (spacing * (packed_items.size() - 1)); // fprintf(stderr, "debug - %p bucket %d fill %d\n", this, bucket, num_fill); // Distribute the bucket over the expandable widgets, position, and draw pos = 0; i = packed_items.begin(); for (int x = 0; i != packed_items.end(); ++i, x++) { int pp, op; if ((*i).widget->GetVisible() == 0) continue; if (packing == 0) { pp = (*i).widget->GetPrefX(); /* op = (*i).widget->GetPrefY(); if (op > ly || op == 0) op = ly; */ op = ly; } else { pp = (*i).widget->GetPrefY(); /* op = (*i).widget->GetPrefX(); if (op > lx || op == 0) op = lx; */ op = lx; } // Disperse the bucket over the items we have left if ((*i).fill != 0 && num_fill != 0) { pp = bucket / num_fill; bucket = bucket - pp; num_fill--; } if (packing == 0) { (*i).widget->SetPosition( sx + pos, sy, sx + pos + pp, sy + op); } else { (*i).widget->SetPosition( sx, sy + pos, sx + op, sy + pos + pp); } pos += pp + spacing; } } void Kis_Panel_Packbox::DrawComponent() { list::iterator i; if (visible == 0) return; for (i = packed_items.begin(); i != packed_items.end(); ++i) { if ((*i).widget->GetLayoutDirty()) { layout_dirty = 1; break; } } if (layout_dirty) { Pack_Widgets(); layout_dirty = 0; } for (i = packed_items.begin(); i != packed_items.end(); ++i) { (*i).widget->DrawComponent(); (*i).widget->SetLayoutDirty(0); } } Kis_Menu::Kis_Menu(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; cur_menu = -1; cur_item = -1; sub_item = -1; sub_menu = -1; mouse_triggered = 0; menuwin = NULL; submenuwin = NULL; text_color = border_color = disable_color = 0; parent_panel->InitColorPref("menu_text_color", "white,blue"); parent_panel->InitColorPref("menu_border_color", "cyan,blue"); parent_panel->InitColorPref("menu_disable_color", "cyan,blue"); } Kis_Menu::~Kis_Menu() { ClearMenus(); if (menuwin != NULL) delwin(menuwin); if (submenuwin != NULL) delwin(submenuwin); } int Kis_Menu::AddMenu(string in_text, int targ_char) { _menu *menu = new _menu; menu->text = in_text; if (targ_char < 0 || targ_char > (int) in_text.length() - 1) menu->targchar = -1; else menu->targchar = targ_char; menu->width = 0; menu->id = menubar.size(); menu->submenu = 0; menu->visible = 1; menu->checked = -1; menubar.push_back(menu); return menu->id; } void Kis_Menu::SetMenuVis(int in_menu, int in_vis) { if (in_menu < 0 || in_menu > (int) menubar.size() - 1) return; menubar[in_menu]->visible = in_vis; } int Kis_Menu::AddMenuItem(string in_text, int menuid, char extra) { if (menuid < 0 || menuid > (int) menubar.size() - 1) return -1; _menuitem *item = new _menuitem; item->parentmenu = menuid; item->text = in_text; item->extrachar = extra; item->id = menubar[menuid]->items.size(); item->visible = 1; item->checked = -1; item->colorpair = -1; item->callback = NULL; item->auxptr = NULL; item->checksymbol = 'X'; if (extra != 0) { for (vector::iterator p = menubar[menuid]->items.begin(); p != menubar[menuid]->items.end(); p++) { if ((*p)->extrachar == extra) { _MSG("New menu item '" + in_text + "' shortcut '" + extra + "' " "conflicts with existing item '" + (*p)->text + "'", MSGFLAG_ERROR); item->extrachar = 0; } } } // Auto-disable spacers if (item->text[0] != '-') item->enabled = 1; else item->enabled = 0; item->submenu = -1; menubar[menuid]->items.push_back(item); if ((int) in_text.length() > menubar[menuid]->width) menubar[menuid]->width = in_text.length(); return (menuid * 100) + item->id + 1; } void Kis_Menu::SetMenuItemChecked(int in_item, int in_checked) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->checked = in_checked; menubar[mid]->checked = -1; // Update the checked menu status for (unsigned int x = 0; x < menubar[mid]->items.size(); x++) { if (menubar[mid]->items[x]->checked > menubar[mid]->checked) menubar[mid]->checked = menubar[mid]->items[x]->checked; } } void Kis_Menu::SetMenuItemColor(int in_item, string in_color) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->colorpair = parent_panel->AddColor(in_color); } int Kis_Menu::AddSubMenuItem(string in_text, int menuid, char extra) { if (menuid < 0 || menuid > (int) menubar.size() - 1) return -1; // Add a new menu to the menu handling system, which gives us // rational IDs and such. int smenuid = AddMenu(in_text, 0); // Mark the new menu record as a submenu so it doesn't get drawn // in the menubar menubar[smenuid]->submenu = 1; // Add a menu item to the requested parent menu, and flag it as a submenu // pointing to our menuid so we can find it during drawing int sitem = AddMenuItem(in_text, menuid, extra); menubar[menuid]->items[(sitem % 100) - 1]->submenu = smenuid; // Return the id of the menu we made so we can add things to it return smenuid; } void Kis_Menu::DisableMenuItem(int in_item) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->enabled = 0; } void Kis_Menu::SetMenuItemCallback(int in_item, kis_menuitem_cb in_cb, void *in_aux) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->callback = in_cb; menubar[mid]->items[iid]->auxptr = in_aux; } void Kis_Menu::ClearMenuItemCallback(int in_item) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->callback = NULL; menubar[mid]->items[iid]->auxptr = NULL; } void Kis_Menu::SetMenuItemCheckSymbol(int in_item, char in_sym) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->checksymbol = in_sym; } void Kis_Menu::EnableMenuItem(int in_item) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->enabled = 1; } void Kis_Menu::EnableAllItems(int in_menu) { if (in_menu < 0 || in_menu >= (int) menubar.size()) return; for (unsigned int x = 0; x < menubar[in_menu]->items.size(); x++) menubar[in_menu]->items[x]->enabled = 1; } void Kis_Menu::DisableAllItems(int in_menu) { if (in_menu < 0 || in_menu >= (int) menubar.size()) return; for (unsigned int x = 0; x < menubar[in_menu]->items.size(); x++) menubar[in_menu]->items[x]->enabled = 0; } void Kis_Menu::SetMenuItemVis(int in_item, int in_vis) { int mid = in_item / 100; int iid = (in_item % 100) - 1; if (mid < 0 || mid >= (int) menubar.size()) return; if (iid < 0 || iid > (int) menubar[mid]->items.size()) return; menubar[mid]->items[iid]->visible = in_vis; } void Kis_Menu::ClearMenus() { // Deconstruct the menubar for (unsigned int x = 0; x < menubar.size(); x++) { for (unsigned int y = 0; y < menubar[x]->items.size(); y++) delete menubar[x]->items[y]; delete menubar[x]; } } int Kis_Menu::FindMenu(string in_menu) { for (unsigned int x = 0; x < menubar.size(); x++) { if (menubar[x]->text == in_menu) return menubar[x]->id; } return -1; } void Kis_Menu::Activate(int subcomponent) { Kis_Panel_Component::Activate(subcomponent); cur_menu = subcomponent - 1; cur_item = -1; sub_menu = -1; sub_item = -1; } void Kis_Menu::Deactivate() { Kis_Panel_Component::Deactivate(); cur_menu = -1; cur_item = -1; sub_menu = -1; sub_item = -1; mouse_triggered = 0; if (submenuwin) { delwin(submenuwin); submenuwin = NULL; } if (menuwin) { delwin(menuwin); menuwin = NULL; } } void Kis_Menu::DrawMenu(_menu *menu, WINDOW *win, int hpos, int vpos) { _menu *submenu = NULL; int subvpos = -1; int subhpos = -1; int dsz = 0; int width_add_check = 0, width_add_en = 0, mod_width = 0; // Resize the menu window, taking invisible items into account, also // figure out the offset for any checked or disabled items for (unsigned int y = 0; y < menu->items.size(); y++) { if (menu->items[y]->visible) { dsz++; if (menu->items[y]->checked > -1) width_add_check = 3; if (menu->items[y]->enabled < 1) width_add_en = 2; } } mod_width = menu->width + 5 + width_add_check + width_add_en; wresize(win, dsz + 2, mod_width); // move it mvderwin(win, vpos, hpos); // Draw the box wattrset(win, border_color); box(win, 0, 0); // Use dsz as the position to draw into dsz = 0; for (unsigned int y = 0; y < menu->items.size(); y++) { string menuline; if (menu->items[y]->visible == 0) continue; // Shortcut out a spacer if (menu->items[y]->text[0] == '-') { wattrset(win, border_color); mvwhline(win, 1 + dsz, 1, ACS_HLINE, mod_width - 1); mvwaddch(win, 1 + dsz, 0, ACS_LTEE); mvwaddch(win, 1 + dsz, mod_width - 1, ACS_RTEE); dsz++; continue; } wattrset(win, text_color); if (menu->items[y]->colorpair != -1) wattrset(win, menu->items[y]->colorpair); // Hilight the current item if (((int) menu->id == cur_menu && (int) y == cur_item) || ((int) menu->id == sub_menu && (int) y == sub_item)) wattron(win, WA_REVERSE); // Draw the check if (menu->items[y]->checked == 1) { string cs = " "; cs[0] = menu->items[y]->checksymbol; menuline += cs; } else if (menu->items[y]->checked == 0 || menu->checked > -1) { menuline += " "; } // Dim a disabled item if (menu->items[y]->enabled == 0) { wattrset(win, disable_color); } // Format it with 'Foo F' if (menu->items[y]->enabled == 0) menuline += "("; menuline += menu->items[y]->text; if (menu->items[y]->enabled == 0) menuline += ")"; menuline += " "; for (unsigned int z = menuline.length(); (int) z <= mod_width - 5; z++) { menuline = menuline + string(" "); } if (menu->items[y]->submenu != -1) { menuline = menuline + ">>"; // Draw again, using our submenu, if it's active if (menu->items[y]->submenu == cur_menu) { submenu = menubar[menu->items[y]->submenu]; subvpos = vpos + dsz; subhpos = hpos + menu->width + 6; } } else if (menu->items[y]->extrachar != 0) { menuline = menuline + " " + menu->items[y]->extrachar; } else { menuline = menuline + " "; } // Print it mvwaddstr(win, 1 + dsz, 1, menuline.c_str()); if (((int) menu->id == cur_menu && (int) y == cur_item) || ((int) menu->id == sub_menu && (int) y == sub_item)) wattroff(win, WA_REVERSE); dsz++; } // Draw the expanded submenu if (subvpos > 0 && subhpos > 0) { if (submenuwin == NULL) submenuwin = derwin(window, 1, 1, 0, 0); DrawMenu(submenu, submenuwin, subhpos, subvpos); } } void Kis_Menu::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(text_color, "menu_text_color"); parent_panel->ColorFromPref(border_color, "menu_border_color"); parent_panel->ColorFromPref(disable_color, "menu_disable_color"); int hpos = 3; if (menuwin == NULL) menuwin = derwin(window, 1, 1, 0, 0); wattron(window, border_color); mvwaddstr(window, sy, sx + 1, "~ "); // Draw the menu bar itself for (unsigned int x = 0; x < menubar.size(); x++) { if (menubar[x]->submenu || menubar[x]->visible == 0) continue; wattron(window, text_color); // If the current menu is the selected one, hilight it if ((int) x == cur_menu || (int) x == sub_menu) wattron(window, WA_REVERSE); // Draw the menu mvwaddstr(window, sy, sx + hpos, (menubar[x]->text).c_str()); // Set the hilight if (menubar[x]->targchar >= 0) { wattron(window, WA_UNDERLINE); mvwaddch(window, sy, sx + hpos + menubar[x]->targchar, menubar[x]->text[menubar[x]->targchar]); wattroff(window, WA_UNDERLINE); } wattroff(window, WA_REVERSE); mvwaddstr(window, sy, sx + hpos + menubar[x]->text.length(), " "); // Draw the menu itself, if we've got an item selected in it if (((int) x == cur_menu || (int) x == sub_menu) && (sub_item >= 0 || cur_item >= 0 || mouse_triggered)) { DrawMenu(menubar[x], menuwin, sx + hpos, sy + 1); } hpos += menubar[x]->text.length() + 1; } wattroff(window, text_color); } void Kis_Menu::FindNextEnabledItem() { int looped = 0; // Handle disabled and spacer items if (menubar[cur_menu]->items[cur_item]->enabled == 0) { // find the next enabled item for (int i = cur_item; i <= (int) menubar[cur_menu]->items.size(); i++) { // Loop if (i >= (int) menubar[cur_menu]->items.size()) { looped = 1; i = 0; } if (looped && i == cur_item) { cur_item = 0; break; } if (menubar[cur_menu]->items[i]->visible == 0) continue; if (menubar[cur_menu]->items[i]->enabled) { cur_item = i; break; } } } } void Kis_Menu::FindPrevEnabledItem() { int looped = 0; // Handle disabled and spacer items if (menubar[cur_menu]->items[cur_item]->enabled == 0) { // find the next enabled item for (int i = cur_item; i >= -1; i--) { // Loop if (i < 0) { i = menubar[cur_menu]->items.size() - 1; looped = 1; } if (looped && i == cur_item) { cur_item = 0; break; } if (menubar[cur_menu]->items[i]->visible == 0) continue; if (menubar[cur_menu]->items[i]->enabled) { cur_item = i; break; } } } } int Kis_Menu::KeyPress(int in_key) { if (visible == 0) return -1; // Activate menu if (in_key == '~' || in_key == '`' || in_key == 0x1B) { if (cur_menu < 0) { Activate(1); } else { // Break out of submenus if (sub_menu != -1) { cur_menu = sub_menu; cur_item = sub_item; sub_menu = sub_item = -1; if (submenuwin) { delwin(submenuwin); submenuwin = NULL; } return 0; } Deactivate(); } // We consume it but the framework doesn't get a state change return -1; } // Menu movement if (in_key == KEY_RIGHT && cur_menu >= 0) { // Break out of submenus on l/r if (sub_menu != -1) { cur_menu = sub_menu; cur_item = sub_item; sub_menu = sub_item = -1; return -1; } for (unsigned int nm = cur_menu + 1; nm < menubar.size(); nm++) { if (menubar[nm]->submenu == 0) { cur_menu = nm; cur_item = 0; FindNextEnabledItem(); break; } } return -1; } if (in_key == KEY_LEFT && cur_menu > 0) { // Break out of submenus on l/r if (sub_menu != -1) { cur_menu = sub_menu; cur_item = sub_item; sub_menu = sub_item = -1; return -1; } for (int nm = cur_menu - 1; nm >= 0; nm--) { if (menubar[nm]->submenu == 0) { cur_menu = nm; cur_item = 0; FindNextEnabledItem(); break; } } return -1; } if (in_key == KEY_DOWN && cur_menu >= 0 && cur_item <= (int) menubar[cur_menu]->items.size() - 1) { if (cur_item == (int) menubar[cur_menu]->items.size() - 1) { cur_item = 0; FindNextEnabledItem(); return -1; } cur_item++; FindNextEnabledItem(); return -1; } if (in_key == KEY_UP && cur_item >= 0) { if (cur_item == 0) { cur_item = menubar[cur_menu]->items.size() - 1; FindPrevEnabledItem(); return -1; } cur_item--; FindPrevEnabledItem(); return -1; } // Space or enter if ((in_key == ' ' || in_key == 0x0A || in_key == KEY_ENTER) && cur_menu >= 0) { if (cur_item == -1) { cur_item = 0; FindNextEnabledItem(); return -1; } // Are we entering a submenu? if (sub_menu == -1 && menubar[cur_menu]->items[cur_item]->submenu != -1) { // Remember where we were sub_menu = cur_menu; sub_item = cur_item; cur_menu = menubar[cur_menu]->items[cur_item]->submenu; cur_item = 0; return -1; } if (menubar[cur_menu]->items[cur_item]->enabled == 0) { FindNextEnabledItem(); return -1; } int ret = (cur_menu * 100) + cur_item + 1; // Per-menu callbacks if (menubar[cur_menu]->items[cur_item]->callback != NULL) (*(menubar[cur_menu]->items[cur_item]->callback))(globalreg, ret, menubar[cur_menu]->items[cur_item]->auxptr); // Widget-wide callbacks if (cb_activate != NULL) (*cb_activate)(this, ret, cb_activate_aux, globalreg); Deactivate(); // Generic fallthrough return ret; } // Key shortcuts if (cur_menu >= 0) { if (cur_item < 0) { // Try w/ the proper case for (unsigned int x = 0; x < menubar.size(); x++) { if (in_key == menubar[x]->text[menubar[x]->targchar]) { cur_menu = x; cur_item = 0; FindNextEnabledItem(); return -1; } } // Try with lowercase, if we didn't find one already for (unsigned int x = 0; x < menubar.size(); x++) { if (tolower(in_key) == tolower(menubar[x]->text[menubar[x]->targchar])) { cur_menu = x; cur_item = 0; FindNextEnabledItem(); return -1; } } return -1; } else { for (unsigned int x = 0; x < menubar[cur_menu]->items.size(); x++) { if (in_key == menubar[cur_menu]->items[x]->extrachar && menubar[cur_menu]->items[x]->enabled == 1) { int ret = (cur_menu * 100) + x + 1; // Per-menu callbacks if (menubar[cur_menu]->items[x]->callback != NULL) { (*(menubar[cur_menu]->items[x]->callback)) (globalreg, ret, menubar[cur_menu]->items[x]->auxptr); } // Widget-wide callbacks if (cb_activate != NULL) (*cb_activate)(this, ret, cb_activate_aux, globalreg); Deactivate(); // Generic fallthrough return ret; } } return -1; } } return 0; } int Kis_Menu::MouseEvent(MEVENT *mevent) { // Menu win/subwin coordinates int wbx, wby, wlx, wly; int match_any_win = 0; if (mevent->bstate == 4 && mevent->y == sy) { // Click happened somewhere in the menubar int hpos = 3; for (unsigned int x = 0; x < menubar.size(); x++) { if (menubar[x]->submenu || menubar[x]->visible == 0) continue; if (mevent->x < hpos) break; if (mevent->x <= hpos + (int) menubar[x]->text.length()) { if ((int) x == cur_menu) { Deactivate(); // Consume w/ no state change to caller return -1; } else { Activate(0); cur_menu = x; cur_item = 0; FindNextEnabledItem(); sub_menu = -1; sub_item = -1; if (submenuwin) { delwin(submenuwin); submenuwin = NULL; } mouse_triggered = 1; // Consume w/ no state change to caller return -1; } } hpos += menubar[x]->text.length() + 1; } /* menu list */ } else if (mevent->bstate == 4 && mevent->y > sy && cur_menu >= 0) { // If we have a submenu if (submenuwin) { // See if we fall w/in it getparyx(submenuwin, wby, wbx); getmaxyx(submenuwin, wly, wlx); // If we're anywhere in the window we don't close menus if (mevent->x >= wbx && mevent->x < wbx + wlx && mevent->y >= wby && mevent->y < wby + wly) match_any_win = 1; // Our range shouldn't include the borders if (mevent->x > wbx && mevent->x < wbx + wlx && mevent->y > wby && mevent->y < wby + wly - 1) { int mitem = mevent->y - wby - 1; if (mitem >= 0 && mitem < (int) menubar[cur_menu]->items.size()) { if (menubar[cur_menu]->items[mitem]->enabled == 1) { int ret = (cur_menu * 100) + mitem + 1; // Per-menu callbacks if (menubar[cur_menu]->items[mitem]->callback != NULL) (*(menubar[cur_menu]->items[mitem]->callback)) (globalreg, ret, menubar[cur_menu]->items[mitem]->auxptr); // Widget-wide callbacks if (cb_activate != NULL) (*cb_activate)(this, ret, cb_activate_aux, globalreg); Deactivate(); return ret; } } } } if (menuwin) { // See if we fall w/in the main menu getparyx(menuwin, wby, wbx); getmaxyx(menuwin, wly, wlx); // If we're anywhere in the window we don't close menus if (mevent->x >= wbx && mevent->x < wbx + wlx && mevent->y >= wby && mevent->y < wby + wly) match_any_win = 1; // Our range shouldn't include the borders if (mevent->x > wbx && mevent->x < wbx + wlx && mevent->y > wby && mevent->y < wby + wly - 1) { // If we had a sub menu, close it if (sub_menu >= 0) { cur_menu = sub_menu; cur_item = sub_item; sub_menu = sub_item = -1; if (submenuwin) { delwin(submenuwin); submenuwin = NULL; } // And drop out of processing now, we don't want to select // the original menu item return -1; } int mitem = mevent->y - wby - 1; if (mitem >= 0 && mitem < (int) menubar[cur_menu]->items.size()) { if (menubar[cur_menu]->items[mitem]->enabled == 1) { // Are we entering a submenu? if (menubar[cur_menu]->items[mitem]->submenu != -1) { // Remember where we were sub_menu = cur_menu; sub_item = cur_item; cur_menu = menubar[cur_menu]->items[mitem]->submenu; cur_item = 0; return -1; } // Otherwise, trigger the menu item int ret = (cur_menu * 100) + mitem + 1; // Per-menu callbacks if (menubar[cur_menu]->items[mitem]->callback != NULL) (*(menubar[cur_menu]->items[mitem]->callback)) (globalreg, ret, menubar[cur_menu]->items[mitem]->auxptr); // Widget-wide callbacks if (cb_activate != NULL) (*cb_activate)(this, ret, cb_activate_aux, globalreg); Deactivate(); return ret; } } } } // Close menus entirely if we're clicking somewhere else in the screen if (match_any_win == 0) { Deactivate(); return -1; } #if 0 int hpos = 3; int ypos = sy + 2; for (unsigned int x = 0; x < (unsigned int) (cur_menu + 1); x++) { if (menubar[x]->submenu || menubar[x]->visible == 0) continue; if (mevent->x < hpos) break; hpos += menubar[x]->text.length() + 1; if (mevent->x <= hpos + (int) menubar[x]->text.length()) { for (unsigned int y = 0; y < menubar[x]->items.size(); y++) { if (menubar[x]->items[y]->visible == 0) continue; if (menubar[x]->items[y]->text[0] == '-') { ypos++; continue; } if (ypos == mevent->y) { if (menubar[x]->items[y]->enabled == 0) return -1; // Trigger the item if (cb_activate != NULL) (*cb_activate)(this, (cur_menu * 100) + y + 1, cb_activate_aux, globalreg); Deactivate(); return (cur_menu * 100) + y + 1; } ypos++; } } } #endif } return 0; } Kis_Free_Text::Kis_Free_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; scroll_pos = 0; SetMinSize(1, 1); alignment = 0; follow_tail = 0; max_text = -1; } Kis_Free_Text::~Kis_Free_Text() { // Nothing } void Kis_Free_Text::DrawComponent() { if (visible == 0) return; int c; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); c = SetTransColor(color_active); if (ly < (int) text_vec.size() && follow_tail && scroll_pos < 0) scroll_pos = text_vec.size() - ly + 1; if (scroll_pos < 0 || scroll_pos > (int) text_vec.size()) scroll_pos = 0; int px = 0; for (unsigned int x = scroll_pos; x < text_vec.size() && px < ly; x++) { // Use the special formatter Kis_Panel_Specialtext::Mvwaddnstr(window, sy + px, sx, text_vec[x], lx - 1, parent_panel, c); px++; } if ((int) text_vec.size() > ly) { // Draw the hash scroll bar mvwvline(window, sy, sx + lx - 1, ACS_VLINE, ly); // Figure out how far down our text we are // int perc = ey * (scroll_pos / text_vec.size()); float perc = (float) ly * (float) ((float) (scroll_pos) / (float) (text_vec.size() - ly)); wattron(window, WA_REVERSE); // Draw the solid position mvwaddch(window, sy + (int) perc, sx + lx - 1, ACS_BLOCK); wattroff(window, WA_REVERSE); } } int Kis_Free_Text::KeyPress(int in_key) { if (visible == 0) return 0; int scrollable = 1; if ((int) text_vec.size() <= ly) scrollable = 0; if (scrollable && in_key == KEY_UP && scroll_pos > 0) { scroll_pos--; return 0; } if (scrollable && in_key == KEY_DOWN && // Don't allow scrolling off the end scroll_pos < ((int) text_vec.size() - ly)) { scroll_pos++; return 0; } if (scrollable && in_key == KEY_PPAGE && scroll_pos > 0) { scroll_pos -= (ly - 1); if (scroll_pos < 0) scroll_pos = 0; return 0; } if (scrollable && in_key == KEY_NPAGE) { scroll_pos += (ly - 1); if (scroll_pos >= ((int) text_vec.size() - ly)) scroll_pos = ((int) text_vec.size() - ly); return 0; } return 1; } void Kis_Free_Text::SetText(string in_text) { text_vec = StrTokenize(in_text, "\n"); SetPreferredSize(Kis_Panel_Specialtext::Strlen(in_text), 1); } void Kis_Free_Text::SetText(vector in_text) { unsigned int ml = 0; for (unsigned x = 0; x < in_text.size(); x++) { if (Kis_Panel_Specialtext::Strlen(in_text[x]) > ml) ml = Kis_Panel_Specialtext::Strlen(in_text[x]); } text_vec = in_text; SetPreferredSize(ml, in_text.size()); if (follow_tail) scroll_pos = -1; } void Kis_Free_Text::AppendText(string in_text) { text_vec.push_back(in_text); if (max_text > 0 && (int) text_vec.size() > max_text) { text_vec.erase(text_vec.begin(), text_vec.begin() + text_vec.size() - max_text); } if (lx < (int) Kis_Panel_Specialtext::Strlen(in_text)) SetPreferredSize(Kis_Panel_Specialtext::Strlen(in_text), text_vec.size()); // If we're following the tail then jump to the bottom when we add text if (ly < (int) text_vec.size() && follow_tail) scroll_pos = text_vec.size() - ly; } void KisStatusText_Messageclient::ProcessMessage(string in_msg, int in_flags) { if ((in_flags & MSGFLAG_INFO)) { ((Kis_Status_Text *) auxptr)->AddLine("\004bINFO\004B: " + in_msg, 6); } else if ((in_flags & MSGFLAG_ERROR)) { ((Kis_Status_Text *) auxptr)->AddLine("\004rERROR\004R: " + in_msg, 7); } else if ((in_flags & MSGFLAG_FATAL)) { ((Kis_Status_Text *) auxptr)->AddLine("\004rFATAL\004R: " + in_msg, 7); } else { ((Kis_Status_Text *) auxptr)->AddLine(in_msg); } } Kis_Status_Text::Kis_Status_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; scroll_pos = 0; status_color_normal = -1; parent_panel->InitColorPref("status_normal_color", "white,black"); } Kis_Status_Text::~Kis_Status_Text() { // Nothing } void Kis_Status_Text::DrawComponent() { parent_panel->ColorFromPref(status_color_normal, "status_normal_color"); if (visible == 0) return; wattrset(window, status_color_normal); for (unsigned int x = 0; x < text_vec.size() && (int) x < ly; x++) { Kis_Panel_Specialtext::Mvwaddnstr(window, ey - x, sx, text_vec[text_vec.size() - x - 1], ex - 1, parent_panel, status_color_normal); } } int Kis_Status_Text::KeyPress(int in_key) { if (visible == 0) return 0; return 1; } void Kis_Status_Text::AddLine(string in_line, int headeroffset) { vector lw = LineWrap(in_line, headeroffset, ex - 1); for (unsigned int x = 0; x < lw.size(); x++) { text_vec.push_back(lw[x]); } if ((int) text_vec.size() > py) { text_vec.erase(text_vec.begin(), text_vec.begin() + text_vec.size() - py); } } Kis_Field_List::Kis_Field_List(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; scroll_pos = 0; field_w = 0; } Kis_Field_List::~Kis_Field_List() { // Nothing } void Kis_Field_List::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); for (unsigned int x = 0; x < field_vec.size() && (int) x < ey; x++) { // Set the field name to bold wattron(window, WA_UNDERLINE); mvwaddnstr(window, sy + x, sx, field_vec[x + scroll_pos].c_str(), field_w); mvwaddch(window, sy + x, sx + field_w, ':'); wattroff(window, WA_UNDERLINE); // Draw the data, leave room on the end for the scrollbar mvwaddnstr(window, sy + x, sx + field_w + 2, data_vec[x + scroll_pos].c_str(), sx - field_w - 3); } if ((int) field_vec.size() > ey) { // Draw the hash scroll bar mvwvline(window, sy, sx + ex - 1, ACS_VLINE, ey); // Figure out how far down our text we are // int perc = ey * (scroll_pos / text_vec.size()); float perc = (float) ey * (float) ((float) (scroll_pos) / (float) (field_vec.size() - ey)); wattron(window, WA_REVERSE); // Draw the solid position mvwaddch(window, sy + (int) perc, sx + ex - 1, ACS_BLOCK); wattroff(window, WA_REVERSE); } } int Kis_Field_List::KeyPress(int in_key) { if (visible == 0) return 0; int scrollable = 1; if ((int) field_vec.size() <= ey) scrollable = 0; if (scrollable && in_key == KEY_UP && scroll_pos > 0) { scroll_pos--; return 0; } if (scrollable && in_key == KEY_DOWN && scroll_pos < ((int) field_vec.size() - ey)) { scroll_pos++; return 0; } if (scrollable && in_key == KEY_PPAGE && scroll_pos > 0) { scroll_pos -= (ey - 1); if (scroll_pos < 0) scroll_pos = 0; return 0; } if (scrollable && in_key == KEY_NPAGE) { scroll_pos += (ey - 1); if (scroll_pos >= ((int) field_vec.size() - ey)) scroll_pos = ((int) field_vec.size() - ey); return 0; } return 1; } int Kis_Field_List::AddData(string in_field, string in_data) { int pos = field_vec.size(); field_vec.push_back(in_field); data_vec.push_back(in_data); if (in_field.length() > field_w) field_w = in_field.length(); return (int) pos; } int Kis_Field_List::ModData(unsigned int in_row, string in_field, string in_data) { if (in_row >= field_vec.size()) return -1; field_vec[in_row] = in_field; data_vec[in_row] = in_data; return (int) in_row; } Kis_Scrollable_Table::Kis_Scrollable_Table(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; scroll_pos = 0; hscroll_pos = 0; selected = -1; SetMinSize(0, 3); draw_lock_scroll_top = 0; draw_highlight_selected = 1; draw_titles = 1; } Kis_Scrollable_Table::~Kis_Scrollable_Table() { for (unsigned int x = 0; x < data_vec.size(); x++) { delete data_vec[x]; } } void Kis_Scrollable_Table::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); // Current character position x int xcur = 0; int ycur = 0; string ftxt; // Assign widths to '0' sized things by dividing what's left // into them. We'll assume the caller doesn't generate a horizontally // scrollable table with variable width fields. int ndynf = 0, spare = lx; if ((int) data_vec.size() > ly) spare -= 1; for (unsigned int x = 0; x < title_vec.size(); x++) { title_vec[x].draw_width = title_vec[x].width; if (title_vec[x].width < 0) continue; if (title_vec[x].width == 0) { ndynf++; continue; } spare -= (title_vec[x].draw_width + 1); } // Distribute the spare over the rest if (spare > 0) { for (unsigned int x = 0; x < title_vec.size() && ndynf > 0; x++) { if (title_vec[x].width == 0) { title_vec[x].draw_width = spare / ndynf; spare -= spare / ndynf--; } } } // Print across the titles if (draw_titles) { wattron(window, WA_UNDERLINE); for (unsigned int x = hscroll_pos; x < title_vec.size() && xcur < lx; x++) { int w = title_vec[x].draw_width; if (xcur + w >= ex) w = lx - xcur; // Align the field w/in the width ftxt = AlignString(title_vec[x].title, ' ', title_vec[x].alignment, w); // Write it out mvwaddstr(window, sy, sx + xcur, ftxt.c_str()); // Advance by the width + 1 xcur += w + 1; } wattroff(window, WA_UNDERLINE); ycur += 1; } if ((int) data_vec.size() > ly) { // Draw the scroll bar mvwvline(window, sy, sx + lx - 1, ACS_VLINE, ly); float perc = (float) ly * (float) ((float) (scroll_pos) / (float) (data_vec.size() - ly)); if (perc > ly - 1) perc = ly - 1; wattron(window, WA_REVERSE); mvwaddch(window, sy + (int) perc, sx + lx - 1, ACS_BLOCK); wattroff(window, WA_REVERSE); } // Jump to the scroll location to start drawing rows for (unsigned int r = scroll_pos ? scroll_pos : 0; r < data_vec.size() && ycur < ly; r++) { // Print across xcur = 0; if ((int) r == selected && draw_highlight_selected) { wattron(window, WA_REVERSE); mvwhline(window, sy + ycur, sx, ' ', lx); } for (unsigned int x = hscroll_pos; x < data_vec[r]->data.size() && xcur < lx && x < title_vec.size(); x++) { int w = title_vec[x].draw_width; if (xcur + w >= lx) w = lx - xcur; ftxt = AlignString(data_vec[r]->data[x], ' ', title_vec[x].alignment, w); mvwaddstr(window, sy + ycur, sx + xcur, ftxt.c_str()); xcur += w + 1; } if ((int) r == selected && draw_highlight_selected) wattroff(window, WA_REVERSE); ycur += 1; } } int Kis_Scrollable_Table::KeyPress(int in_key) { if (visible == 0) return 0; int scrollable = 1; if ((int) data_vec.size() < ly) scrollable = 0; // Selected up one, scroll up one if we need to if (in_key == KEY_UP) { if (draw_highlight_selected == 0 && scrollable) { // If we're not drawing the highlights then we don't mess // with the selected item at all, we just slide the scroll // pos up and down, and make sure we don't let them scroll // off the end of the world, keep as much of the tail in view // as possible if (scroll_pos > 0) scroll_pos--; } else if (selected > 0) { selected--; if (scrollable && scroll_pos > 0 && scroll_pos > selected) { scroll_pos--; } } } if (in_key == KEY_DOWN && selected < (int) data_vec.size() - 1) { if (draw_highlight_selected == 0 && scrollable) { // If we're not drawing the highlights then we don't mess // with the selected item at all, we just slide the scroll // pos up and down, and make sure we don't let them scroll // off the end of the world, keep as much of the tail in view // as possible if (scroll_pos + ly <= (int) data_vec.size() - 1) scroll_pos++; } else if (draw_lock_scroll_top && scrollable && scroll_pos + ly - 1 <= selected) { // If we're locked to always keep the list filled, we can only // scroll until the bottom is visible. This implies we don't // show the selected row, too selected++; scroll_pos++; } else { selected++; if (scrollable && scroll_pos + ly - 1 <= selected) { scroll_pos++; } } } if (in_key == KEY_RIGHT && hscroll_pos < (int) title_vec.size() - 1) { hscroll_pos++; } if (in_key == KEY_LEFT && hscroll_pos > 0) { hscroll_pos--; } if (in_key == '\n' || in_key == '\r' || in_key == ' ') { if (cb_activate != NULL) (*cb_activate)(this, GetSelected(), cb_activate_aux, globalreg); return GetSelected(); } return 0; } int Kis_Scrollable_Table::GetSelected() { if (selected >= 0 && selected < (int) data_vec.size()) { return data_vec[selected]->key; } return -1; } vector Kis_Scrollable_Table::GetRow(int in_key) { vector ret; if (in_key >= 0 && in_key < (int) data_vec.size()) { return data_vec[in_key]->data; } return ret; } vector Kis_Scrollable_Table::GetSelectedData() { vector ret; if (selected >= 0 && selected < (int) data_vec.size()) { return data_vec[selected]->data; } return ret; } int Kis_Scrollable_Table::SetSelected(int in_key) { for (unsigned int x = 0; x < data_vec.size(); x++) { if (data_vec[x]->key == in_key) { selected = x; return 1; } } return 0; } int Kis_Scrollable_Table::AddTitles(vector in_titles) { title_vec = in_titles; return 1; } int Kis_Scrollable_Table::AddRow(int in_key, vector in_fields) { if (key_map.find(in_key) != key_map.end()) { _MSG("Scrollable_Table tried to add row already keyed", MSGFLAG_ERROR); return -1; } if (in_fields.size() != title_vec.size()) { _MSG("Scrollable_Table added row with a different number of fields than " "the title", MSGFLAG_ERROR); } row_data *r = new row_data; r->key = in_key; r->data = in_fields; key_map[in_key] = 1; data_vec.push_back(r); SetPreferredSize(0, data_vec.size() + 2); return 1; } int Kis_Scrollable_Table::DelRow(int in_key) { if (key_map.find(in_key) == key_map.end()) { // _MSG("Scrollable_Table tried to del row that doesn't exist", MSGFLAG_ERROR); return -1; } key_map.erase(key_map.find(in_key)); for (unsigned int x = 0; x < data_vec.size(); x++) { if (data_vec[x]->key == in_key) { delete data_vec[x]; data_vec.erase(data_vec.begin() + x); break; } } if (scroll_pos >= (int) data_vec.size()) { scroll_pos = data_vec.size() - 1; if (scroll_pos < 0) scroll_pos = 0; } if (selected >= (int) data_vec.size()) { selected = data_vec.size() - 1; } return 1; } int Kis_Scrollable_Table::ReplaceRow(int in_key, vector in_fields) { if (key_map.find(in_key) == key_map.end()) { // Add a row instead return AddRow(in_key, in_fields); #if 0 _MSG("Scrollable_Table tried to replace row that doesn't exist", MSGFLAG_ERROR); return -1; #endif } for (unsigned int x = 0; x < data_vec.size(); x++) { if (data_vec[x]->key == in_key) { data_vec[x]->data = in_fields; break; } } return 1; } void Kis_Scrollable_Table::Clear() { for (unsigned int x = 0; x < data_vec.size(); x++) delete data_vec[x]; data_vec.clear(); key_map.clear(); return; } Kis_Single_Input::Kis_Single_Input(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; curs_pos = 0; inp_pos = 0; label_pos = LABEL_POS_NONE; max_len = 0; draw_len = 0; } Kis_Single_Input::~Kis_Single_Input() { // Nothing } void Kis_Single_Input::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); int xoff = 0; int yoff = 0; // Draw the label if we can, in bold if (ly >= 2 && label_pos == LABEL_POS_TOP) { wattron(window, WA_BOLD); mvwaddnstr(window, sy, sx, label.c_str(), lx); wattroff(window, WA_BOLD); yoff = 1; } else if (label_pos == LABEL_POS_LEFT) { wattron(window, WA_BOLD); mvwaddnstr(window, sy, sx, label.c_str(), lx); wattroff(window, WA_BOLD); xoff += label.length() + 1; } // set the drawing length draw_len = lx - xoff; if (draw_len < 0) draw_len = 0; // Don't let us fall behind start if (curs_pos < 0) curs_pos = 0; // Clean up any silliness that might be present from initialization if (inp_pos - curs_pos >= draw_len) curs_pos = inp_pos - draw_len + 1; // Reset the default color again since we messed with bold attributes SetTransColor(color_active); // Invert for the text wattron(window, WA_REVERSE); /* draw the inverted line */ mvwhline(window, sy + yoff, sx + xoff, ' ', draw_len); if (curs_pos >= (int) text.length()) curs_pos = 0; // fprintf(stderr, "debug - about to try to substr %d %d from len %d\n", curs_pos, draw_len, text.length()); /* draw the text from cur to what fits */ mvwaddnstr(window, sy + yoff, sx + xoff, text.substr(curs_pos, draw_len).c_str(), draw_len); /* Underline & unreverse the last character of the text (or space) */ wattroff(window, WA_REVERSE); if (active) { wattron(window, WA_UNDERLINE); char ch; if (inp_pos < (int) text.length()) ch = text[inp_pos]; else ch = ' '; mvwaddch(window, sy + yoff, sx + xoff + (inp_pos - curs_pos), ch); wattroff(window, WA_UNDERLINE); } } int Kis_Single_Input::KeyPress(int in_key) { if (visible == 0 || draw_len == 0) return 0; // scroll left, and move the viewing window if we have to if (in_key == KEY_LEFT && inp_pos > 0) { inp_pos--; if (inp_pos < curs_pos) curs_pos = inp_pos; return 0; } // scroll right, and move the viewing window if we have to if (in_key == KEY_RIGHT && inp_pos < (int) text.length()) { inp_pos++; if (inp_pos - curs_pos >= draw_len) curs_pos = inp_pos - draw_len + 1; return 0; } // Catch home/end (if we can) if (in_key == KEY_HOME) { inp_pos = 0; curs_pos = 0; return 0; } if (in_key == KEY_END) { inp_pos = text.length(); curs_pos = inp_pos - draw_len + 1; return 0; } // Catch deletes if ((in_key == KEY_BACKSPACE || in_key == 0x7F) && text.length() > 0) { if (inp_pos == 0) inp_pos = 1; text.erase(text.begin() + (inp_pos - 1)); if (inp_pos > 0) inp_pos--; if (inp_pos < curs_pos) curs_pos = inp_pos; return 0; } // Lastly, if the character is in our filter of allowed characters for typing, // and if we have room, insert it and scroll to the right if ((int) text.length() < max_len && filter_map.find(in_key) != filter_map.end()) { char ins[2] = { in_key, 0 }; text.insert(inp_pos, ins); inp_pos++; if (inp_pos - curs_pos >= draw_len) curs_pos = inp_pos - draw_len + 1; return 0; } return 0; } int Kis_Single_Input::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) { // Single input only does a focus switch on mouse events if (cb_switch != NULL) (*cb_switch)(this, 1, cb_switch_aux, globalreg); return 1; } return 0; } void Kis_Single_Input::SetCharFilter(string in_charfilter) { filter_map.clear(); for (unsigned int x = 0; x < in_charfilter.length(); x++) { filter_map[in_charfilter[x]] = 1; } } void Kis_Single_Input::SetLabel(string in_label, KisWidget_LabelPos in_pos) { label = in_label; label_pos = in_pos; SetPreferredSize(label.length() + max_len + 1, 1); SetMinSize(label.length() + 3, 1); } void Kis_Single_Input::SetTextLen(int in_len) { max_len = in_len; SetPreferredSize(in_len + label.length() + 1, 1); SetMinSize(label.length() + 3, 1); } void Kis_Single_Input::SetText(string in_text, int dpos, int ipos) { text = in_text; if (ipos < 0) inp_pos = in_text.length(); else inp_pos = ipos; if (dpos < 0) curs_pos = 0; else curs_pos = dpos; } string Kis_Single_Input::GetText() { return text; } Kis_Button::Kis_Button(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; SetMinSize(3, 1); } Kis_Button::~Kis_Button() { // nada } void Kis_Button::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); // Draw the highlighted button area if we're active if (active) wattron(window, WA_REVERSE); mvwhline(window, sy, sx, ' ', lx); // Center the text int tx = (lx / 2) - (text.length() / 2); mvwaddnstr(window, sy, sx + tx, text.c_str(), lx - tx); // Add the ticks mvwaddch(window, sy, sx, '['); mvwaddch(window, sy, sx + lx - 1, ']'); if (active) wattroff(window, WA_REVERSE); } int Kis_Button::KeyPress(int in_key) { if (visible == 0) return 0; if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } return 0; } int Kis_Button::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) { if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } return 0; } void Kis_Button::SetText(string in_text) { text = in_text; SetPreferredSize(text.length() + 4, 1); } Kis_Checkbox::Kis_Checkbox(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; checked = 0; } Kis_Checkbox::~Kis_Checkbox() { // nada } void Kis_Checkbox::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); // Draw the highlighted button area if we're active if (active) wattron(window, WA_REVERSE); mvwhline(window, sy, sx, ' ', lx); if (checked) { mvwaddnstr(window, sy, sx, "[X]", 3); } else { mvwaddnstr(window, sy, sx, "[ ]", 3); } mvwaddnstr(window, sy, sx + 4, text.c_str(), lx - 4); if (active) wattroff(window, WA_REVERSE); } void Kis_Checkbox::Activate(int subcomponent) { active = 1; } void Kis_Checkbox::Deactivate() { active = 0; } int Kis_Checkbox::KeyPress(int in_key) { if (visible == 0) return 0; if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') { checked = !checked; if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 0; } return 0; } int Kis_Checkbox::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) { checked = !checked; if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } return 0; } void Kis_Checkbox::SetText(string in_text) { text = in_text; SetPreferredSize(text.length() + 4, 1); } int Kis_Checkbox::GetChecked() { return checked; } void Kis_Checkbox::SetChecked(int in_check) { checked = in_check; } Kis_Radiobutton::Kis_Radiobutton(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; checked = 0; } Kis_Radiobutton::~Kis_Radiobutton() { // nada } void Kis_Radiobutton::DrawComponent() { if (visible == 0) return; parent_panel->ColorFromPref(color_active, color_active_pref); parent_panel->ColorFromPref(color_inactive, color_inactive_pref); SetTransColor(color_active); // Draw the highlighted button area if we're active if (active) wattron(window, WA_REVERSE); mvwhline(window, sy, sx, ' ', lx); if (checked) { mvwaddnstr(window, sy, sx, "(*)", 3); } else { mvwaddnstr(window, sy, sx, "( )", 3); } mvwaddnstr(window, sy, sx + 4, text.c_str(), lx - 4); if (active) wattroff(window, WA_REVERSE); } void Kis_Radiobutton::Activate(int subcomponent) { active = 1; } void Kis_Radiobutton::Deactivate() { active = 0; } int Kis_Radiobutton::KeyPress(int in_key) { if (visible == 0) return 0; if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') { if (!checked) SetChecked(1); if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 0; } return 0; } int Kis_Radiobutton::MouseEvent(MEVENT *mevent) { int mwx, mwy; getbegyx(window, mwy, mwx); mwx = mevent->x - mwx; mwy = mevent->y - mwy; if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) { if (!checked) SetChecked(1); if (cb_activate != NULL) (*cb_activate)(this, 1, cb_activate_aux, globalreg); return 1; } return 0; } void Kis_Radiobutton::SetText(string in_text) { text = in_text; SetPreferredSize(text.length() + 4, 1); } int Kis_Radiobutton::GetChecked() { return checked; } void Kis_Radiobutton::SetChecked(int in_check) { checked = in_check; for (unsigned int x = 0; x < linked_vec.size() && in_check; x++) linked_vec[x]->SetChecked(0); } void Kis_Radiobutton::LinkRadiobutton(Kis_Radiobutton *in_button) { linked_vec.push_back(in_button); } void Kis_IntGraph::AddExtDataVec(string name, int layer, string colorpref, string colordefault, char line, char fill, int overunder, vector *in_dv) { graph_source gs; gs.layer = layer; gs.colorpref = colorpref; gs.colordefault = colordefault; gs.colorval = 0; snprintf(gs.line, 2, "%c", line); snprintf(gs.fill, 2, "%c", fill); gs.data = in_dv; gs.name = name; gs.overunder = overunder; // Can't figure out how to do a sort template of a template class, so hell // with it, we'll do it sloppily here. Assembled least to greatest priority for (unsigned int x = 0; x < data_vec.size(); x++) { if (layer < data_vec[x].layer) { data_vec.insert(data_vec.begin() + x, gs); return; } } if (name.length() > maxlabel) maxlabel = name.length(); // Add it to the end otherwise data_vec.push_back(gs); } int Kis_IntGraph::KeyPress(int in_key) { // Nothing to do for now return 1; } void Kis_IntGraph::DrawComponent() { if (visible == 0) return; char backing[32]; parent_panel->ColorFromPref(color_fw, color_active_pref); for (unsigned int x = 0; x < data_vec.size(); x++) { parent_panel->InitColorPref(data_vec[x].colorpref, data_vec[x].colordefault); parent_panel->ColorFromPref(data_vec[x].colorval, data_vec[x].colorpref); } // We want the same scale for over/under, so we'll calculate the // height as h - 1 (label) (div 2 if o/u) int gh = (ly - 1) / (graph_mode == 1 ? 2 : 1) - xgraph_size; // Zero position on the graph is the bottom, or center, depending // on normal or over/under int gzero = ey - (graph_mode == 1 ? gh : 1) - xgraph_size; // Width - label int gw = lx; unsigned int gxofft; // Set the drawing max and min int dmax_y = max_y; int dmin_y = min_y; // Go through the list and get the max if we're auto-scaling if (max_y == 0 || min_y == 0) { for (unsigned int x = 0; x < data_vec.size(); x++) { for (unsigned int z = 0; z < data_vec[x].data->size(); z++) { if (max_y == 0 && (((*(data_vec[x].data))[z] > 0 && dmax_y < (*(data_vec[x].data))[z]) || ((*(data_vec[x].data))[z] < 0 && dmax_y > (*(data_vec[x].data))[z]))) dmax_y = (*(data_vec[x].data))[z]; } } } // adjust the drawing size snprintf(backing, 32, " %d ", dmax_y); gxofft = strlen(backing); snprintf(backing, 32, " %d ", dmin_y); if (strlen(backing) > gxofft) gxofft = strlen(backing); gw -= gxofft; // Go through from least to greatest priority so that the "high" priority // draws over the old for (unsigned int x = 0; x < data_vec.size(); x++) { int xmod = 0; int xgroup = 1; int dvsize = data_vec[x].data->size(); if (inter_x) { xmod = (int) ceilf((float) dvsize / (float) gw); xgroup = xmod * 2; } for (int gx = 0; (gx < gw) && inter_x; gx++) { int r = 0, py, nuse = 0; // We make the assumption here that T is a numerical // type in some fashion, if this is ever not true we'll have // to do something else // int avg = 0; int max = 0; // Interpolate down if we have too much data if (gw < dvsize) { // Center of the samples we look at r = (int) (((float) gx / (float) gw) * (float) dvsize); // Determine the local max across our range for (int pos = -1 * (xgroup / 2); pos < (xgroup / 2); pos++) { if (r + pos >= dvsize || r + pos < 0) { continue; } // Max depending on if we're neg or pos data if ((*(data_vec[x].data))[r + pos] >= 0 && (*(data_vec[x].data))[r + pos] > max) { if ((*(data_vec[x].data))[r+pos] > dmax_y) { max = dmax_y; } else { max = (*(data_vec[x].data))[r + pos]; } } else if ((*(data_vec[x].data))[r + pos] < 0 && (*(data_vec[x].data))[r + pos] < max) { if ((*(data_vec[x].data))[r+pos] < dmin_y) { max = dmin_y; } else { max = (*(data_vec[x].data))[r + pos]; } } nuse++; } } else { nuse = 1; unsigned int pos = (unsigned int) (((float) gx/gw) * dvsize); if (pos >= (*(data_vec)[x].data).size() || pos < 0) { max = min_y; } else { max = (*(data_vec)[x].data)[pos]; } } if (nuse == 0) { continue; } // If we're negative, do the math differently // Adapt the group max to our scale float adapted = 0; if (max < 0) { adapted = (float) (abs(max) + dmin_y) / (float) (abs(dmax_y) + dmin_y); } else { adapted = (float) (max - min_y) / (float) (dmax_y - min_y); } // Scale it to the height of the graph py = (int) ((float) gh * adapted); // Set the color once wattrset(window, data_vec[x].colorval); // If we're plotting over/normal, we do nothing // If we're plotting under, we invert and draw below int oumod = 1; if (data_vec[x].overunder < 0 && graph_mode == 1) oumod = -1; for (int gy = gh; gy >= 0; gy--) { if (gy == py) mvwaddstr(window, gzero - (gy * oumod), sx + gx + gxofft, data_vec[x].line); else if (gy < py) mvwaddstr(window, gzero - (gy * oumod), sx + gx + gxofft, data_vec[x].fill); } } int rwidth = (int) kismin(2, (1.0f / dvsize) * gw); for (int dvx = 0; dvx < dvsize && inter_x == 0; dvx++) { int py = 0; int max = (*(data_vec)[x].data)[dvx]; int drawx = (int) (((float) dvx / dvsize) * gw); // If we're negative, do the math differently // Adapt the group max to our scale float adapted = 0; if (max < 0) { adapted = (float) (abs(max) + dmin_y) / (float) (abs(dmax_y) + dmin_y); } else { adapted = (float) (max - min_y) / (float) (dmax_y - min_y); } // Scale it to the height of the graph py = (int) ((float) gh * adapted); // Set the color once wattrset(window, data_vec[x].colorval); for (int rdx = rwidth * -1; rdx < rwidth; rdx++) { // If we're plotting over/normal, we do nothing // If we're plotting under, we invert and draw below int oumod = 1; if (data_vec[x].overunder < 0 && graph_mode == 1) oumod = -1; for (int gy = gh; gy >= 0; gy--) { if (gy == py) mvwaddstr(window, gzero - (gy * oumod), sx + drawx + rdx + gxofft, data_vec[x].line); else if (gy < py && data_vec[x].fill) mvwaddstr(window, gzero - (gy * oumod), sx + drawx + rdx + gxofft, data_vec[x].fill); } } } } if (draw_layers) { // Draw the labels (right-hand) int posmod = 0, negmod = 0; // Set the backing blank memset(backing, ' ', 32); if ((maxlabel + 4) >= 32) maxlabel = (32 - 4); backing[maxlabel + 4] = '\0'; // Draw the component name labels for (unsigned int x = 0; x < data_vec.size(); x++) { // Position int lpos = 0; // Text color if (data_vec[x].overunder < 0 && graph_mode == 1) { lpos = ey - negmod++; } else { lpos = sy + posmod++; } // Fill in the blocking wattrset(window, color_fw); mvwaddstr(window, lpos, ex - (maxlabel + 4), backing); // Fill in the label mvwaddstr(window, lpos, ex - (maxlabel), data_vec[x].name.c_str()); // Fill in the colors wattrset(window, data_vec[x].colorval); mvwaddstr(window, lpos, ex - (maxlabel + 3), data_vec[x].line); mvwaddstr(window, lpos, ex - (maxlabel + 2), data_vec[x].fill); } } // Draw the X marker labels wattrset(window, color_fw); for (unsigned int x = 0; x < label_x.size() && label_x_graphref >= 0; x++) { // GX within the # of samples on the graph int lgx = (int) (((float) gw / data_vec[label_x_graphref].data->size()) * label_x[x].position); for (unsigned int y = 0; y < label_x[x].label.size(); y++) { mvwaddch(window, gzero + y + 1, sx + lgx + gxofft, label_x[x].label[y]); } } // Reuse the backing for the scale if (draw_scale) { snprintf(backing, 32, " %d ", dmax_y); wattrset(window, color_fw); mvwaddstr(window, sy, sx, backing); wattrset(window, color_fw); mvwhline(window, gzero, sx, ACS_HLINE, lx); snprintf(backing, 32, " %d ", min_y); mvwaddstr(window, gzero, sx, backing); } } #if 0 int Kis_PolarGraph::KeyPress(int in_key) { return 1; } void Kis_PolarGraph::DrawComponent() { if (visible == 0) return; // Square ourselves to the shortest dimension if (lx < ly) ly = lx; else lx = ly; parent_panel->InitColorPref(color_active_pref, "white,black"); parent_panel->ColorFromPref(color_fw, color_active_pref); for (unsigned int x = 0; x < point_vec.size(); x++) { // Real position int px = (lx / 2) + point_vec[x].r * sin(point_vec[x].theta) * (lx / 2); int py = (ly / 2) - point_vec[x].r * cos(point_vec[x].theta) * (lx / 2); // fprintf(stderr, "debug - graph %s pos %d %d\n", point_vec[x].name.c_str(), px, py); // Plot the text at the position //wattrset(window, point_vec[x].colorval); // Plot w/in boundaries mvwaddnstr(window, sy + py, sx + px, point_vec[x].name.c_str(), point_vec[x].name.length()); } } void Kis_PolarGraph::AddPoint(int id, graph_point gp) { parent_panel->InitColorPref(gp.colorpref, gp.colordefault); parent_panel->ColorFromPref(gp.colorval, gp.colorpref); gp.id = id; if (fabs(gp.r) > maxr) maxr = fabs(gp.r); for (unsigned int x = 0; x < point_vec.size(); x++) { if (point_vec[x].id == id) { point_vec[x] = gp; return; } } point_vec.push_back(gp); } void Kis_PolarGraph::DelPoint(int id) { maxr = 0; for (unsigned int x = 0; x < point_vec.size(); x++) { if (point_vec[x].id == id) { point_vec.erase(point_vec.begin() + x); x--; continue; } if (fabs(point_vec[x].r) > maxr) maxr = fabs(point_vec[x].r); } } void Kis_PolarGraph::ClearPoints() { maxr = 0; point_vec.clear(); } Kis_Filepicker::Kis_Filepicker(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Scrollable_Table(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; vector titles; Kis_Scrollable_Table::title_data t; t.width = 0; t.title = "File"; t.alignment = 0; titles.push_back(t); AddTitles(titles); SetDrawTitles(0); SetLockScrollTop(1); } Kis_Filepicker::~Kis_Filepicker() { } void Kis_Filepicker::SetDirectory(string in_dir) { DIR *dir; struct dirent *file; struct stat sbuf; vector content; if (in_dir == cur_directory) return; if (in_dir[in_dir.length() - 1] != '/') in_dir += "/"; cur_directory = in_dir; if ((dir = opendir(in_dir.c_str())) == NULL) { content.push_back("[ Invalid Directory:"); content.push_back(string(" ") + in_dir + string(" ]")); return; } while ((file = readdir(dir)) != NULL) { if (string(file->d_name) == ".") continue; if (stat(file->d_name, &sbuf) < 0) continue; if (S_ISDIR(sbuf.st_mode)) { string n = string(file->d_name); if (n != "..") n += "/"; content.push_back(n); } } rewinddir(dir); while ((file = readdir(dir)) != NULL) { if (stat(file->d_name, &sbuf) < 0) continue; if (S_ISREG(sbuf.st_mode)) { content.push_back(string(file->d_name)); } } closedir(dir); vector td; td.push_back(""); for (unsigned int x = 0; x < content.size(); x++) { td[0] = content[x]; ReplaceRow(x, td); } SetFile(set_file); } void Kis_Filepicker::SetFile(string in_file) { set_file = in_file; if (set_file == "") return; for (unsigned int x = 0; x < data_vec.size(); x++) { if (data_vec[x]->data[0] == set_file) { SetSelected(x); return; } } } int Kis_Filepicker::KeyPress(int in_key) { struct stat sbuf; if (visible == 0) return 0; if (data_vec.size() > 0 && (in_key == '\n' || in_key == '\r' || in_key == ' ')) { vector sel = GetSelectedData(); if (sel.size() == 1) { if (stat(string(cur_directory + sel[0]).c_str(), &sbuf) == 0) { if (sel[0] == "..") { if (sel[0].rfind("/") != string::npos) { SetDirectory(sel[0].substr(0, sel[0].rfind("/"))); } } else if (S_ISDIR(sbuf.st_mode)) { SetDirectory(cur_directory + sel[0]); return 0; } } } } return Kis_Scrollable_Table::KeyPress(in_key); } #endif Kis_Panel::Kis_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) { globalreg = in_globalreg; kpinterface = in_intf; win = newwin(1, 1, 0, 0); pan = new_panel(win); hide_panel(pan); menu = NULL; text_color = border_color = 0; InitColorPref("panel_text_color", "white,black"); InitColorPref("panel_border_color", "blue,black"); ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); sx = sy = sizex = sizey = 0; active_component = NULL; main_component = NULL; tab_pos = -1; last_key = 0; last_key_time.tv_sec = 0; escape_timer = -1; } Kis_Panel::~Kis_Panel() { for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if (pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_STATIC) continue; delete pan_comp_vec[x].comp; } if (pan != NULL) del_panel(pan); if (win != NULL) delwin(win); } void Kis_Panel::AddComponentVec(Kis_Panel_Component *in_comp, int in_flags) { component_entry etr; etr.comp_flags = in_flags; etr.comp = in_comp; pan_comp_vec.push_back(etr); } void Kis_Panel::DelComponentVec(Kis_Panel_Component *in_comp) { for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if (pan_comp_vec[x].comp == in_comp) { pan_comp_vec.erase(pan_comp_vec.begin() + x); return; } } } void Kis_Panel::SetActiveComponent(Kis_Panel_Component *in_comp) { for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if (pan_comp_vec[x].comp == in_comp) { active_component = in_comp; tab_pos = x; in_comp->Activate(0); } else { pan_comp_vec[x].comp->Deactivate(); } } } int Kis_Panel::KeyPress(int in_key) { int ret; if (menu) { ret = menu->KeyPress(in_key); if (ret != 0) return 0; } // figure out if we need to get to a visible item first and jump to it via the // tab function if (active_component != NULL && active_component->GetVisible() == 0 && in_key != '\t') KeyPress('\t'); if (in_key == '\t' && tab_pos >= 0) { int set = -1; // Find from current to end for (unsigned int x = tab_pos + 1; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) == 0 || (pan_comp_vec[x].comp->GetVisible() == 0)) continue; set = x; break; } // No? Find from start if (set == -1) { for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) == 0 || (pan_comp_vec[x].comp->GetVisible() == 0)) continue; set = x; break; } } // No? Someone deleted the tabable components then, just stop if (set == -1) { tab_pos = -1; return 0; } pan_comp_vec[tab_pos].comp->Deactivate(); tab_pos = set; pan_comp_vec[tab_pos].comp->Activate(1); active_component = pan_comp_vec[tab_pos].comp; } if (active_component != NULL) { ret = active_component->KeyPress(in_key); return 0; } return 0; } int Kis_Panel::MouseEvent(MEVENT *mevent) { int ret; // We just process every component until we get a non-0 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_EVT) == 0) continue; ret = pan_comp_vec[x].comp->MouseEvent(mevent); if (ret != 0) { // Positive response means switch the focus if (ret >= 0) { if (active_component != NULL) active_component->Deactivate(); if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) && tab_pos >= 0) { tab_pos = x; } active_component = pan_comp_vec[x].comp; active_component->Activate(0); } return 0; } } return 0; } void Kis_Panel::InitColorPref(string in_pref, string in_def) { if (kpinterface->prefs->FetchOpt(in_pref) == "") kpinterface->prefs->SetOpt(in_pref, in_def, 1); } void Kis_Panel::ColorFromPref(int &clr, string in_pref) { /* if (kpinterface->prefs->FetchOptDirty(in_pref) || clr == 0) { kpinterface->prefs->SetOptDirty(in_pref, 0); */ clr = kpinterface->colors.AddColor(kpinterface->prefs->FetchOpt(in_pref), in_pref); /* } */ return; } void Kis_Panel::RemapAllColors(string oldcolor, string newcolor) { kpinterface->colors.RemapAllColors(oldcolor, newcolor, kpinterface->prefs); } int Kis_Panel::AddColor(string in_color) { return kpinterface->colors.AddColor(in_color, ""); } void Kis_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) { sx = in_sx; sy = in_sy; sizex = in_x; sizey = in_y; if (win == NULL) { win = newwin(sizey, sizex, sy, sx); } if (pan == NULL) { pan = new_panel(win); } else { wresize(win, sizey, sizex); replace_panel(pan, win); move_panel(pan, sy, sx); ClearPanel(); } keypad(win, true); meta(win, true); if (menu != NULL) menu->SetPosition(1, 0, 0, 0); if (main_component != NULL) main_component->SetPosition(1, 1, in_x - 1, in_y - 2); } int kp_escape_timer(TIMEEVENT_PARMS) { // fprintf(stderr, "trigger escape timer %u %u\n", globalreg->timestamp.tv_sec, globalreg->timestamp.tv_usec); ungetch(0x00); ((Kis_Panel *) parm)->Poll(); return 0; } int Kis_Panel::Poll() { if (globalreg->spindown) return 0; int get = wgetch(win); MEVENT mevent; int ret; int escape_timer_possible = 1; /* // Timeout on our internal escape handler struct timeval key_diff; SubtractTimeval(&(globalreg->timestamp), &last_key_time, &key_diff); if (key_diff.tv_sec > 1 || key_diff.tv_usec > 500000) { last_key = 0; } last_key_time.tv_sec = globalreg->timestamp.tv_sec; last_key_time.tv_usec = globalreg->timestamp.tv_usec; */ if (escape_timer > 0) { globalreg->timetracker->RemoveTimer(escape_timer); escape_timer = -1; // Don't allow requeuing a second timer on a timered escape escape_timer_possible = 0; } // If we're getting triggered from the timer callback if (get == 0x00) { get = 0x1b; } if (get == 0x1b && last_key != 0x1b) { last_key = 0x1b; // fprintf(stderr, "schedule escape timer %u %u\n", globalreg->timestamp.tv_sec, globalreg->timestamp.tv_usec); if (escape_timer_possible) { escape_timer = globalreg->timetracker->RegisterTimer(2, NULL, 0, &kp_escape_timer, this); return 1; } } else if (last_key == 0x1b && get == 0x5b) { last_key = 0x5b; return 1; } else if (last_key == 0x5b) { switch (get) { case 0x41: get = KEY_UP; break; case 0x42: get = KEY_DOWN; break; case 0x43: get = KEY_RIGHT; break; case 0x44: get = KEY_LEFT; break; default: break; } } else { last_key = 0; } if (get == KEY_MOUSE) { getmouse(&mevent); ret = MouseEvent(&mevent); } else { // fprintf(stderr, "debug - passing key %02x\n", get); ret = KeyPress(get); } // If we can't trigger a timer, this means we came in from a timer, // which means we should force an extra interface redraw to handle what // it may have changed, we don't get our normal redraw since we didn't get // a real keypress if (escape_timer_possible == 0) kpinterface->DrawInterface(); if (ret < 0) return ret; return 1; } void Kis_Panel::SetTitle(string in_title) { title = in_title; } void Kis_Panel::DrawTitleBorder() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wattrset(win, border_color); box(win, 0, 0); wattron(win, WA_UNDERLINE); mvwaddstr(win, 0, 3, title.c_str()); wattroff(win, WA_UNDERLINE); wattrset(win, text_color); } void Kis_Panel::DrawComponentVec() { wattrset(win, text_color); for (unsigned int x = 0; x < pan_comp_vec.size(); x++) { if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_DRAW) == 0) continue; pan_comp_vec[x].comp->DrawComponent(); } if (menu != NULL) menu->DrawComponent(); } #endif kismet-2013-03-R1b/kis_pktproto.h0000664000175000017500000001036512124602454016361 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PKTPROTO_H__ #define __KIS_PKTPROTO_H__ #include "config.h" #include "util.h" #include "netframework.h" #include "ipc_remote.h" // Packet control IPC protocol // Elements requested from the parent should include the ID they'll // be referred to in the return frames // Parent->Child - Add a packet source // SOURCEADD // sourceline - standard config file source line // type - our dervied type from the server, easier than trying to figure out // autotype on the IPC // channel source data - everything we parsed from the server and derived for // channel sharing // Channel source data may be reset once we have parsed more about this source, // by sending a channelset struct ipc_source_add { uint16_t source_id; char type[64]; char sourceline[1024]; uint16_t channel_id; uint32_t channel; int32_t channel_hop; int32_t channel_dwell; int32_t channel_rate; int32_t channel_position; }; // Parent->Child - Push a channel list, we assume we'll never // need to set more than 256 channels in this rev, expandable // if we need to in the future. // An existing channel set may be re-used by sending this packet // a second time with the same chanset id // SOURCEADDCHAN // chanset_hop_offset allows hopping multiple channels at a time to force // mixing on iterative lists (cur chan + hop offset = next chan) // dwell list should be populated with dwelling points equivalent to the // channel set #define IPC_SOURCE_MAX_CHANS 256 struct ipc_source_add_chanlist { uint16_t chanset_id; uint16_t num_channels; struct chandata_t { union { struct { // Highest bit (1<<15) == 0 if channel uint16_t channel; uint16_t dwell; } chan_t; struct { // Highest bit (1<<15) == 1 if range uint16_t start; uint16_t end; uint16_t width; uint16_t iter; } range_t; } u; } chandata[IPC_SOURCE_MAX_CHANS]; /* uint32_t chan_list[IPC_SOURCE_MAX_CHANS]; uint8_t chan_dwell_list[IPC_SOURCE_MAX_CHANS]; */ }; // Parent->Child - Set a channel set or specific channel // SOURCESETCHAN // chanset_id = 0 && hop = 0 implies lock to channel // // Used to lock/unlock hopping or change channel sets runtime, also to modify // hop/dwell status struct ipc_source_chanset { uint16_t source_id; uint16_t chanset_id; uint32_t channel; int32_t channel_hop; int32_t channel_dwell; int32_t channel_rate; int32_t channel_split; uint16_t channel_pos; }; // Parent->Child - Start/Stop a source // SOURCERUN struct ipc_source_run { uint16_t source_id; uint8_t start; }; // Child->Parent - Report a frame // SOURCEFRAME struct ipc_source_packet { uint16_t source_id; uint32_t tv_sec; uint32_t tv_usec; uint32_t dlt; uint32_t pkt_len; uint8_t data[0]; }; // Child-Parent - Report source state. Sent once per second on // non-hopping sources, once per hop cycle complete on hopping // sources, or in the event of an error. msgbus link will carry // the data regarding the error until we need more detailed // per-source failure state info // SOURCESTATE struct ipc_source_report { uint16_t source_id; uint16_t chanset_id; uint32_t capabilities; uint8_t flags; uint32_t hop_tm_sec; uint32_t hop_tm_usec; uint32_t last_channel; }; #define IPC_SRCREP_FLAG_NONE 0 #define IPC_SRCREP_FLAG_RUNNING 1 #define IPC_SRCREP_FLAG_ERROR 128 // Child-Parent - Report channel timings struct ipc_source_chanreport { uint16_t num_channels; uint32_t channels[IPC_SOURCE_MAX_CHANS]; uint16_t channels_time[IPC_SOURCE_MAX_CHANS]; }; // Parent-Child - Remove packet source struct ipc_source_remove { uint16_t source_id; }; #endif kismet-2013-03-R1b/alertracker.cc0000664000175000017500000002677112124602454016276 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "alertracker.h" #include "configfile.h" const char *ALERT_fields_text[] = { "sec", "usec", "header", "bssid", "source", "dest", "other", "channel", "text", NULL }; // alert. data = ALERT_data int Protocol_ALERT(PROTO_PARMS) { kis_alert_info *info = (kis_alert_info *) data; ostringstream osstr; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= ALERT_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch(fnum) { case ALERT_header: cache->Cache(fnum, info->header); break; case ALERT_sec: osstr << (int) info->tm.tv_sec; cache->Cache(fnum, osstr.str()); break; case ALERT_usec: osstr << (int) info->tm.tv_usec; cache->Cache(fnum, osstr.str()); break; case ALERT_bssid: cache->Cache(fnum, info->bssid.Mac2String()); break; case ALERT_source: cache->Cache(fnum, info->source.Mac2String()); break; case ALERT_dest: cache->Cache(fnum, info->dest.Mac2String()); break; case ALERT_other: cache->Cache(fnum, info->other.Mac2String()); break; case ALERT_channel: osstr << info->channel; cache->Cache(fnum, osstr.str()); break; case ALERT_text: cache->Cache(fnum, "\001" + info->text + "\001"); break; default: out_string = "Unknown field requested."; return -1; break; } // print the newly filled in cache out_string += cache->GetCache(fnum) + " "; } return 1; } void Protocol_ALERT_enable(PROTO_ENABLE_PARMS) { globalreg->alertracker->BlitBacklogged(in_fd); } Alertracker::Alertracker() { fprintf(stderr, "*** Alertracker::Alertracker() called with no global registry. Bad.\n"); } Alertracker::Alertracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; next_alert_id = 0; if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Alertracker called with null config\n"); exit(1); } if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Alertracker called with null packetchain\n"); exit(1); } if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: Alertracker called with null kisnetserver\n"); exit(1); } if (globalreg->kismet_config->FetchOpt("alertbacklog") != "") { int scantmp; if (sscanf(globalreg->kismet_config->FetchOpt("alertbacklog").c_str(), "%d", &scantmp) != 1 || scantmp < 0) { globalreg->messagebus->InjectMessage("Illegal value for 'alertbacklog' " "in config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } num_backlog = scantmp; } // Register the alert component _PCM(PACK_COMP_ALERT) = globalreg->packetchain->RegisterPacketComponent("alert"); // Register the alert protocol _NPM(PROTO_REF_ALERT) = globalreg->kisnetserver->RegisterProtocol("ALERT", 0, 1, ALERT_fields_text, &Protocol_ALERT, &Protocol_ALERT_enable, this); // Register a KISMET alert type with no rate restrictions _ARM(ALERT_REF_KISMET) = RegisterAlert("KISMET", sat_day, 0, sat_day, 0); // Parse config file vector of all alerts if (ParseAlertConfig(globalreg->kismet_config) < 0) { _MSG("Failed to parse alert values from Kismet config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Created alert tracker...", MSGFLAG_INFO); } Alertracker::~Alertracker() { for (map::iterator x = alert_ref_map.begin(); x != alert_ref_map.end(); ++x) delete x->second; } int Alertracker::RegisterAlert(const char *in_header, alert_time_unit in_unit, int in_rate, alert_time_unit in_burstunit, int in_burst) { char err[1024]; // Bail if this header is registered if (alert_name_map.find(in_header) != alert_name_map.end()) { snprintf(err, 1024, "RegisterAlert() header already registered '%s'", in_header); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } // Bail if the rates are impossible if (in_burstunit > in_unit) { snprintf(err, 1024, "Registering alert '%s' failed, time unit for " "burst rate must be <= time unit for max rate", in_header); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } alert_rec *arec = new alert_rec; arec->ref_index = next_alert_id++; arec->header = StrUpper(in_header); arec->limit_unit = in_unit; arec->burst_unit = in_burstunit; arec->limit_rate = in_rate; arec->limit_burst = in_burst; arec->burst_sent = 0; arec->time_last = 0; alert_name_map[arec->header] = arec->ref_index; alert_ref_map[arec->ref_index] = arec; return arec->ref_index; } int Alertracker::FetchAlertRef(string in_header) { if (alert_name_map.find(in_header) != alert_name_map.end()) return alert_name_map[in_header]; return -1; } int Alertracker::CheckTimes(alert_rec *arec) { // Is this alert rate-limited? If not, shortcut out and send it if (arec->limit_rate == 0) { return 1; } struct timeval now; gettimeofday(&now, NULL); // If the last time we sent anything was longer than the main rate limit, // then we reset back to empty if (arec->time_last < (now.tv_sec - alert_time_unit_conv[arec->limit_unit])) { arec->total_sent = 0; arec->burst_sent = 0; return 1; } // If the last time we sent anything was longer than the burst rate, we can // reset the burst to 0 if (arec->time_last < (now.tv_sec - alert_time_unit_conv[arec->burst_unit])) { arec->burst_sent = 0; } // If we're under the limit on both, we're good to go if (arec->burst_sent < arec->limit_burst && arec->total_sent < arec->limit_rate) return 1; return 0; } int Alertracker::PotentialAlert(int in_ref) { map::iterator aritr = alert_ref_map.find(in_ref); if (aritr == alert_ref_map.end()) return -1; alert_rec *arec = aritr->second; return CheckTimes(arec); } int Alertracker::RaiseAlert(int in_ref, kis_packet *in_pack, mac_addr bssid, mac_addr source, mac_addr dest, mac_addr other, int in_channel, string in_text) { map::iterator aritr = alert_ref_map.find(in_ref); if (aritr == alert_ref_map.end()) return -1; alert_rec *arec = aritr->second; if (CheckTimes(arec) != 1) return 0; kis_alert_info *info = new kis_alert_info; info->header = arec->header; gettimeofday(&(info->tm), NULL); info->bssid = bssid; info->source = source; info->dest = dest; info->other = other; info->channel = in_channel; info->text = in_text; // Increment and set the timers arec->burst_sent++; arec->total_sent++; arec->time_last = time(0); alert_backlog.push_back(info); if ((int) alert_backlog.size() > num_backlog) { delete alert_backlog[0]; alert_backlog.erase(alert_backlog.begin()); } // Try to get the existing alert info if (in_pack != NULL) { kis_alert_component *acomp = (kis_alert_component *) in_pack->fetch(_PCM(PACK_COMP_ALERT)); // if we don't have an alert container, make one on this packet if (acomp == NULL) { acomp = new kis_alert_component; in_pack->insert(_PCM(PACK_COMP_ALERT), acomp); } // Attach it to the packet acomp->alert_vec.push_back(info); } // Send it to the network as an alert globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_ALERT), (void *) info); // Send the text info globalreg->messagebus->InjectMessage((info->header + " " + info->text), MSGFLAG_ALERT); return 1; } void Alertracker::BlitBacklogged(int in_fd) { for (unsigned int x = 0; x < alert_backlog.size(); x++) { kis_protocol_cache cache; globalreg->kisnetserver->SendToClient(in_fd, _NPM(PROTO_REF_ALERT), (void *) alert_backlog[x], &cache); } } int Alertracker::ParseAlertStr(string alert_str, string *ret_name, alert_time_unit *ret_limit_unit, int *ret_limit_rate, alert_time_unit *ret_limit_burst, int *ret_burst_rate) { char err[1024]; vector tokens = StrTokenize(alert_str, ","); if (tokens.size() != 3) { snprintf(err, 1024, "Malformed limits for alert '%s'", alert_str.c_str()); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } (*ret_name) = StrLower(tokens[0]); if (ParseRateUnit(StrLower(tokens[1]), ret_limit_unit, ret_limit_rate) != 1 || ParseRateUnit(StrLower(tokens[2]), ret_limit_burst, ret_burst_rate) != 1) { snprintf(err, 1024, "Malformed limits for alert '%s'", alert_str.c_str()); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } return 1; } // Split up a rate/unit string into real values int Alertracker::ParseRateUnit(string in_ru, alert_time_unit *ret_unit, int *ret_rate) { char err[1024]; vector units = StrTokenize(in_ru, "/"); if (units.size() == 1) { // Unit is per minute if not specified (*ret_unit) = sat_minute; } else { // Parse the string unit if (units[1] == "sec" || units[1] == "second") { (*ret_unit) = sat_second; } else if (units[1] == "min" || units[1] == "minute") { (*ret_unit) = sat_minute; } else if (units[1] == "hr" || units[1] == "hour") { (*ret_unit) = sat_hour; } else if (units[1] == "day") { (*ret_unit) = sat_day; } else { snprintf(err, 1024, "Alertracker - Invalid time unit for alert rate '%s'", units[1].c_str()); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } } // Get the number if (sscanf(units[0].c_str(), "%d", ret_rate) != 1) { snprintf(err, 1024, "Alertracker - Invalid rate '%s' for alert", units[0].c_str()); globalreg->messagebus->InjectMessage(err, MSGFLAG_ERROR); return -1; } return 1; } int Alertracker::ParseAlertConfig(ConfigFile *in_conf) { vector clines = in_conf->FetchOptVec("alert"); for (unsigned int x = 0; x < clines.size(); x++) { alert_conf_rec *rec = new alert_conf_rec; if (ParseAlertStr(clines[x], &(rec->header), &(rec->limit_unit), &(rec->limit_rate), &(rec->burst_unit), &(rec->limit_burst)) < 0) { _MSG("Invalid alert line in config file: " + clines[x], MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } alert_conf_map[StrLower(rec->header)] = rec; } return 1; } int Alertracker::ActivateConfiguredAlert(const char *in_header) { string hdr = StrLower(in_header); if (alert_conf_map.find(hdr) == alert_conf_map.end()) { _MSG("Alert type " + string(in_header) + " not found in list of activated " "alerts.", MSGFLAG_INFO); return -1; } alert_conf_rec *rec = alert_conf_map[hdr]; return RegisterAlert(rec->header.c_str(), rec->limit_unit, rec->limit_rate, rec->burst_unit, rec->limit_burst); } const vector *Alertracker::FetchBacklog() { return (const vector *) &alert_backlog; } kismet-2013-03-R1b/battery.h0000664000175000017500000000206112124602454015275 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __BATTERY_H__ #define __BATTERY_H__ #include "config.h" #include #include #include #include #include #include #include struct kis_battery_info { int percentage, charging, ac, remaining_sec; }; int Fetch_Battery_Info(kis_battery_info *out_info); #endif kismet-2013-03-R1b/ringbuf.cc0000664000175000017500000001241612124602454015422 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ringbuf.h" #include RingBuffer::RingBuffer(int in_size) { ring_len = in_size; ring_data = new uint8_t[in_size]; ring_rptr = ring_data; ring_wptr = ring_data; } RingBuffer::~RingBuffer() { delete[] ring_data; } int RingBuffer::InsertDummy(int in_len) { if (ring_wptr == ring_rptr && ring_wptr == ring_data) return 1; if (ring_wptr + in_len >= ring_data + ring_len) { int tail = (ring_data + ring_len) - ring_wptr; if (ring_data + (in_len - tail) >= ring_rptr) return 0; } else { if ((ring_rptr > ring_wptr) && (ring_wptr + in_len >= ring_rptr)) return 0; } return 1; } int RingBuffer::InsertData(uint8_t *in_data, int in_len) { // Will this hit the end of the ring and go back to the beginning? if ((ring_wptr + in_len) >= (ring_data + ring_len)) { // How much data gets written to the tail of the ring before we // wrap? int tail = (ring_data + ring_len) - ring_wptr; // If we're going to wrap, will we overrun the read position? if (ring_data + (in_len - tail) >= ring_rptr) return 0; // Copy the data to the end of the loop, move to the beginning memcpy(ring_wptr, in_data, tail); memcpy(ring_data, in_data + tail, in_len - tail); ring_wptr = ring_data + (in_len - tail); } else { // Will we surpass the read pointer? if ((ring_rptr > ring_wptr) && (ring_wptr + in_len >= ring_rptr)) return 0; // Copy the data to the write pointer memcpy(ring_wptr, in_data, in_len); ring_wptr = ring_wptr + in_len; } // printf("debug - inserted %d into ring buffer.\n", in_len); return 1; } int RingBuffer::FetchLen() { int ret = 0; if (ring_wptr < ring_rptr) { // If the write pointer is wrapped before the read, add the // length from read to the end plus the beginning to the write ret = (ring_data + ring_len) - ring_rptr + (ring_wptr - ring_data); } else { ret = (ring_wptr - ring_rptr); } //printf("ring begin %p wptr %p rptr %p lt %d len %d\n", //ring_data, ring_wptr, ring_rptr, ring_wptr < ring_rptr, ret); return ret; } void RingBuffer::FetchPtr(uint8_t *in_dataptr, int in_max, int *in_len) { // Has the write pointer looped back? if (ring_wptr < ring_rptr) { // Copy the read to the end, as much as we can *in_len = (ring_data + ring_len) - ring_rptr; // If we have more room than we need if (*in_len > in_max) { // printf("debug - ring %d avail, %d requested\n", *in_len, in_max); *in_len = in_max; memcpy(in_dataptr, ring_rptr, in_max); return; } // Copy all we can to the end of the array memcpy(in_dataptr, ring_rptr, *in_len); // How many bytes can we copy? Whichever is smaller - the head of the // ring, or the max we can hold after we stocked it before int copybytes = kismin((ring_wptr - ring_data), (in_max - *in_len)); // Copy it off the header memcpy(in_dataptr + *in_len, ring_data, copybytes); *in_len = *in_len + copybytes; return; } else { // Copy out the requested size or as much as we can *in_len = kismin((ring_wptr - ring_rptr), in_max); memcpy(in_dataptr, ring_rptr, *in_len); return; } } void RingBuffer::MarkRead(int in_len) { // Will we loop the array? if ((ring_rptr + in_len) >= (ring_data + ring_len)) { // How much comes off the length before we wrap? int tail = (ring_data + ring_len) - ring_rptr; // Catch surpassing the write pointer after the loop if (ring_data + (in_len - tail) > ring_wptr) ring_rptr = ring_wptr; else ring_rptr = ring_data + (in_len - tail); } else { ring_rptr += in_len; } //printf("debug - marked %d read in ring\n", in_len); return; } int RingBuffer::FetchSize() { return ring_len; } int RingBuffer::Resize(int in_newlen) { if (in_newlen < ring_len) return 0; // New buffer uint8_t *newdata = new uint8_t[in_newlen]; // Copy old data memcpy(ring_data, newdata, ring_len); // Offset the pointers into the ring buf by the same # of bytes that they // were into the old buf ring_wptr = newdata + (ring_wptr - ring_data); ring_rptr = newdata + (ring_rptr - ring_data); // Remove the old, copy the new delete[] ring_data; ring_data = newdata; ring_len = in_newlen; return 1; } kismet-2013-03-R1b/packetsource_airpcap.h0000664000175000017500000000640112124602454020014 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Ported from the kismet-stable airpcap source, contrbuted by Loris of CACE */ #ifndef __PACKETSOURCE_AIRPCAP_H__ #define __PACKETSOURCE_AIRPCAP_H__ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(HAVE_LIBAIRPCAP) && defined(SYS_CYGWIN) // This is a bad thing to do, but windows.h totally breaks c++ strings, // which is also unacceptable. extern "C" { // Some Windows-specific definitions. They are normally imported by // including windows.h, but we don't do it because of conflicts with the // rest of cygwin typedef unsigned int ULONG, *PULONG; typedef int LONG, *PLONG; typedef unsigned int UINT, *PUINT; typedef int INT, *PINT; typedef int BOOL, *PBOOL; typedef unsigned short USHORT, *PUSHORT; typedef short SHORT, *PSHORT; typedef unsigned char UCHAR, *PUCHAR; typedef signed char CHAR, *PCHAR; typedef unsigned char BYTE, *PBYTE; typedef void VOID, *PVOID; typedef void *HANDLE; typedef unsigned long long ULONGLONG, *PULONGLONG; #include } #include "cygwin_utils.h" #include "packet.h" #include "packet_ieee80211.h" #include "packetsource.h" #include "packetsource_pcap.h" #ifdef HAVE_LOCALRADIOTAP #include "local_ieee80211_radiotap.h" #endif #define USE_PACKETSOURCE_AIRPCAP // Another pcap variant, with some local overriding hooks class PacketSource_AirPcap : public PacketSource_Pcap { public: PacketSource_AirPcap() { fprintf(stderr, "FATAL OOPS: Packetsource_Airpcap() called\n"); exit(1); } PacketSource_AirPcap(GlobalRegistry *in_globalreg) : PacketSource_Pcap(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_AirPcap(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_AirPcap(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_AirPcap() { } virtual int OpenSource(); virtual int Poll(); virtual int FetchDescriptor(); virtual int FetchChannelCapable() { return 1; } virtual int EnableMonitor(); virtual int DisableMonitor(); virtual int SetChannel(unsigned int in_ch); virtual int FetchHardwareChannel(); virtual vector FetchSupportedChannels(string in_interface); protected: virtual void FetchRadioData(kis_packet *in_packet) { }; PAirpcapHandle airpcap_handle; HANDLE winpcap_evthandle; Handle2Fd fd_mangle; }; #endif /* cygwin */ #endif kismet-2013-03-R1b/timetracker.cc0000664000175000017500000001062712124602454016302 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include "timetracker.h" Timetracker::Timetracker() { fprintf(stderr, "Timetracker::Timetracker() called with no globalreg\n"); } Timetracker::Timetracker(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; next_timer_id = 0; globalreg->start_time = time(0); gettimeofday(&(globalreg->timestamp), NULL); } Timetracker::~Timetracker() { // Free the events for (map::iterator x = timer_map.begin(); x != timer_map.end(); ++x) delete x->second; } int Timetracker::Tick() { // Handle scheduled events struct timeval cur_tm; gettimeofday(&cur_tm, NULL); globalreg->timestamp.tv_sec = cur_tm.tv_sec; globalreg->timestamp.tv_usec = cur_tm.tv_usec; timer_event *evt; for (unsigned int x = 0; x < sorted_timers.size(); x++) { evt = sorted_timers[x]; if ((cur_tm.tv_sec < evt->trigger_tm.tv_sec) || ((cur_tm.tv_sec == evt->trigger_tm.tv_sec) && (cur_tm.tv_usec < evt->trigger_tm.tv_usec))) { // fprintf(stderr, "debug - tick at %u %u - queue is all older\n", cur_tm.tv_sec, cur_tm.tv_usec); return 1; } // Call the function with the given parameters int ret; ret = (*evt->callback)(evt, evt->callback_parm, globalreg); if (ret > 0 && evt->timeslices != -1 && evt->recurring) { evt->schedule_tm.tv_sec = cur_tm.tv_sec; evt->schedule_tm.tv_usec = cur_tm.tv_usec; evt->trigger_tm.tv_sec = evt->schedule_tm.tv_sec + (evt->timeslices / 10); evt->trigger_tm.tv_usec = evt->schedule_tm.tv_usec + (100000 * (evt->timeslices % 10)); if (evt->trigger_tm.tv_usec > 999999) { evt->trigger_tm.tv_usec = evt->trigger_tm.tv_usec - 1000000; evt->trigger_tm.tv_sec++; } // Resort the list stable_sort(sorted_timers.begin(), sorted_timers.end(), SortTimerEventsTrigger()); } else { RemoveTimer(evt->timer_id); } } return 1; } int Timetracker::RegisterTimer(int in_timeslices, struct timeval *in_trigger, int in_recurring, int (*in_callback)(TIMEEVENT_PARMS), void *in_parm) { timer_event *evt = new timer_event; evt->timer_id = next_timer_id++; gettimeofday(&(evt->schedule_tm), NULL); if (in_trigger != NULL) { evt->trigger_tm.tv_sec = in_trigger->tv_sec; evt->trigger_tm.tv_usec = in_trigger->tv_usec; evt->timeslices = -1; } else { evt->trigger_tm.tv_sec = evt->schedule_tm.tv_sec + (in_timeslices / 10); evt->trigger_tm.tv_usec = evt->schedule_tm.tv_usec + (in_timeslices % 10); evt->timeslices = in_timeslices; } evt->recurring = in_recurring; evt->callback = in_callback; evt->callback_parm = in_parm; timer_map[evt->timer_id] = evt; sorted_timers.push_back(evt); // Resort the list stable_sort(sorted_timers.begin(), sorted_timers.end(), SortTimerEventsTrigger()); return evt->timer_id; } int Timetracker::RemoveTimer(int in_timerid) { map::iterator itr; itr = timer_map.find(in_timerid); if (itr != timer_map.end()) { for (unsigned int x = 0; x < sorted_timers.size(); x++) { if (sorted_timers[x]->timer_id == in_timerid) sorted_timers.erase(sorted_timers.begin() + x); } // Resort the list stable_sort(sorted_timers.begin(), sorted_timers.end(), SortTimerEventsTrigger()); delete itr->second; timer_map.erase(itr); return 1; } return -1; } kismet-2013-03-R1b/iwcontrol.cc0000664000175000017500000005563412124602454016017 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "iwcontrol.h" #ifdef SYS_LINUX #include #include #include #include #include #include #ifdef HAVE_LINUX_WIRELESS #include #include #include #ifndef rintf #define rintf(x) (float) rint((double) (x)) #endif float IwFreq2Float(iwreq *inreq) { return ((float) inreq->u.freq.m) * pow(10,inreq->u.freq.e); } void IwFloat2Freq(double in_val, struct iw_freq *out_freq) { if (in_val <= 165) { out_freq->m = (uint32_t) in_val; out_freq->e = 0; return; } out_freq->e = (short) (floor(log10(in_val))); if(out_freq->e > 8) { out_freq->m = ((long) (floor(in_val / pow(10,out_freq->e - 6)))) * 100; out_freq->e -= 8; } else { out_freq->m = (uint32_t) in_val; out_freq->e = 0; } } int FloatChan2Int(float in_chan) { if (in_chan > 0 && in_chan < 165) return (int) in_chan; int mod_chan = (int) rintf(in_chan / 1000000); int x = 0; // 80211b frequencies to channels int IEEE80211Freq[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200, 5210, 5220, 5240, 5250, 5260, 5280, 5290, 5300, 5320, 5745, 5760, 5765, 5785, 5800, 5805, 5825, -1 }; int IEEE80211Ch[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 42, 44, 48, 50, 52, 56, 58, 60, 64, 149, 152, 153, 157, 160, 161, 165 }; while (IEEE80211Freq[x] != -1) { if (IEEE80211Freq[x] == mod_chan) { return IEEE80211Ch[x]; } x++; } return mod_chan; } int Iwconfig_Set_SSID(const char *in_dev, char *errstr, const char *in_essid) { struct iwreq wrq; int skfd; char essid[IW_ESSID_MAX_SIZE + 1]; if (in_essid == NULL) { essid[0] = '\0'; } else { // Trim transparently snprintf(essid, IW_ESSID_MAX_SIZE+1, "%s", in_essid); } if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create ioctl socket to set SSID on %s: %s", in_dev, strerror(errno)); return -1; } // Zero the ssid strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); wrq.u.essid.pointer = (caddr_t) essid; wrq.u.essid.length = strlen(essid)+1; wrq.u.essid.flags = 1; if (ioctl(skfd, SIOCSIWESSID, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to set SSID on %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } int Iwconfig_Get_SSID(const char *in_dev, char *errstr, char *in_essid) { struct iwreq wrq; int skfd; char essid[IW_ESSID_MAX_SIZE + 1]; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create socket to fetch SSID on %s: %s", in_dev, strerror(errno)); return -1; } strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); wrq.u.essid.pointer = (caddr_t) essid; wrq.u.essid.length = IW_ESSID_MAX_SIZE+1; wrq.u.essid.flags = 0; if (ioctl(skfd, SIOCGIWESSID, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to fetch SSID from %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } snprintf(in_essid, kismin(IW_ESSID_MAX_SIZE, wrq.u.essid.length) + 1, "%s", (char *) wrq.u.essid.pointer); close(skfd); return 0; } int Iwconfig_Get_Name(const char *in_dev, char *errstr, char *in_name) { struct iwreq wrq; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create socket to get name on %s: %s", in_dev, strerror(errno)); return -1; } strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIWNAME, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to get name on %s :%s", in_dev, strerror(errno)); close(skfd); return -1; } snprintf(in_name, IFNAMSIZ, "%s", wrq.u.name); close(skfd); return 0; } // Set a private ioctl that takes 1 or 2 integer parameters // A return of -2 means no privctl found that matches, so that the caller // can return a more detailed failure message // // Code largely taken from wireless_tools int Iwconfig_Set_IntPriv(const char *in_dev, const char *privcmd, int val1, int val2, char *errstr) { struct iwreq wrq; int skfd; struct iw_priv_args priv[IW_MAX_PRIV_DEF]; u_char buffer[4096]; int subcmd = 0; int offset = 0; memset(priv, 0, sizeof(priv)); if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create socket to set private ioctl on %s: %s", in_dev, strerror(errno)); return -1; } memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); wrq.u.data.pointer = (caddr_t) priv; wrq.u.data.length = IW_MAX_PRIV_DEF; wrq.u.data.flags = 0; if (ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to retrieve list of private ioctls on %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } int pn = -1; while ((++pn < wrq.u.data.length) && strcmp(priv[pn].name, privcmd)); if (pn == wrq.u.data.length) { snprintf(errstr, STATUS_MAX, "Unable to find private ioctl '%s' on %s", privcmd, in_dev); close(skfd); return -2; } // Find subcmds, as if this isn't ugly enough already if (priv[pn].cmd < SIOCDEVPRIVATE) { int j = -1; while ((++j < wrq.u.data.length) && ((priv[j].name[0] != '\0') || (priv[j].set_args != priv[pn].set_args) || (priv[j].get_args != priv[pn].get_args))); if (j == wrq.u.data.length) { snprintf(errstr, STATUS_MAX, "Unable to find subioctl '%s' on %s", privcmd, in_dev); close(skfd); return -2; } subcmd = priv[pn].cmd; offset = sizeof(__u32); pn = j; } // Make sure its an iwpriv we can set if ((priv[pn].set_args & IW_PRIV_TYPE_MASK) == 0 || (priv[pn].set_args & IW_PRIV_SIZE_MASK) == 0) { snprintf(errstr, STATUS_MAX, "Unable to set values for private ioctl '%s' on %s", privcmd, in_dev); close(skfd); return -1; } if ((priv[pn].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) { snprintf(errstr, STATUS_MAX, "'%s' on %s does not accept integer parameters.", privcmd, in_dev); close(skfd); return -1; } // Find out how many arguments it takes and die if we can't handle it int nargs = (priv[pn].set_args & IW_PRIV_SIZE_MASK); if (nargs > 2) { snprintf(errstr, STATUS_MAX, "Private ioctl '%s' on %s expects more than " "2 arguments.", privcmd, in_dev); close(skfd); return -1; } // Build the set request memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); // Assign the arguments wrq.u.data.length = nargs; ((__s32 *) buffer)[0] = (__s32) val1; if (nargs > 1) { ((__s32 *) buffer)[1] = (__s32) val2; } // This is terrible! // This is also simplified from what iwpriv.c does, because we don't // need to worry about get-no-set ioctls if ((priv[pn].set_args & IW_PRIV_SIZE_FIXED) && ((sizeof(__u32) * nargs) + offset <= IFNAMSIZ)) { if (offset) wrq.u.mode = subcmd; memcpy(wrq.u.name + offset, buffer, IFNAMSIZ - offset); } else { wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.flags = 0; } // Actually do it. if (ioctl(skfd, priv[pn].cmd, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to set private ioctl '%s' on %s: %s", privcmd, in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } int Iwconfig_Get_IntPriv(const char *in_dev, const char *privcmd, int *val, char *errstr) { struct iwreq wrq; int skfd; struct iw_priv_args priv[IW_MAX_PRIV_DEF]; u_char buffer[4096]; int subcmd = 0; int offset = 0; memset(priv, 0, sizeof(priv)); if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create socket to fetch private ioctl on %s: %s", in_dev, strerror(errno)); return -1; } memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); wrq.u.data.pointer = (caddr_t) priv; wrq.u.data.length = IW_MAX_PRIV_DEF; wrq.u.data.flags = 0; if (ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to retrieve list of private ioctls on %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } int pn = -1; while ((++pn < wrq.u.data.length) && strcmp(priv[pn].name, privcmd)); if (pn == wrq.u.data.length) { snprintf(errstr, STATUS_MAX, "Unable to find private ioctl '%s' on %s", privcmd, in_dev); close(skfd); return -2; } // Find subcmds, as if this isn't ugly enough already if (priv[pn].cmd < SIOCDEVPRIVATE) { int j = -1; while ((++j < wrq.u.data.length) && ((priv[j].name[0] != '\0') || (priv[j].set_args != priv[pn].set_args) || (priv[j].get_args != priv[pn].get_args))); if (j == wrq.u.data.length) { snprintf(errstr, STATUS_MAX, "Unable to find subioctl '%s' on %s", privcmd, in_dev); close(skfd); return -2; } subcmd = priv[pn].cmd; offset = sizeof(__u32); pn = j; } // Make sure its an iwpriv we can set if ((priv[pn].get_args & IW_PRIV_TYPE_MASK) == 0 || (priv[pn].get_args & IW_PRIV_SIZE_MASK) == 0) { snprintf(errstr, STATUS_MAX, "Unable to get values for private ioctl '%s' on %s", privcmd, in_dev); close(skfd); return -1; } if ((priv[pn].get_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) { snprintf(errstr, STATUS_MAX, "Private ioctl '%s' on %s does not return " "integer parameters.", privcmd, in_dev); close(skfd); return -1; } // Find out how many arguments it takes and die if we can't handle it int nargs = (priv[pn].get_args & IW_PRIV_SIZE_MASK); if (nargs > 1) { snprintf(errstr, STATUS_MAX, "Private ioctl '%s' on %s returns more than 1 " "parameter and we can't handle that at the moment.", privcmd, in_dev); close(skfd); return -1; } // Build the get request memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); // Assign the arguments wrq.u.data.length = 0L; // This is terrible! // Simplified (again) from iwpriv, since we split the command into // a set and a get instead of combining the cases if ((priv[pn].get_args & IW_PRIV_SIZE_FIXED) && ((sizeof(__u32) * nargs) + offset <= IFNAMSIZ)) { /* Second case : no SET args, GET args fit within wrq */ if (offset) wrq.u.mode = subcmd; } else { wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.flags = 0; } // Actually do it. if (ioctl(skfd, priv[pn].cmd, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "Failed to call get private ioctl '%s' on %s: %s", privcmd, in_dev, strerror(errno)); close(skfd); return -1; } // Where do we get the data from? if ((priv[pn].get_args & IW_PRIV_SIZE_FIXED) && ((sizeof(__u32) * nargs) + offset <= IFNAMSIZ)) memcpy(buffer, wrq.u.name, IFNAMSIZ); // Return the value of the ioctl (*val) = ((__s32 *) buffer)[0]; close(skfd); return 0; } int Iwconfig_Get_Levels(const char *in_dev, char *in_err, int *level, int *noise) { struct iwreq wrq; struct iw_range range; struct iw_statistics stats; char buffer[sizeof(iw_range) * 2]; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(in_err, STATUS_MAX, "Failed to create AF_INET DGRAM socket %d:%s", errno, strerror(errno)); return -1; } // Fetch the range memset(buffer, 0, sizeof(iw_range) * 2); memset(&wrq, 0, sizeof(struct iwreq)); wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = sizeof(buffer); wrq.u.data.flags = 0; strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) { snprintf(in_err, STATUS_MAX, "Failed to fetch signal range, %s", strerror(errno)); close(skfd); return -1; } // Pull it out memcpy((char *) &range, buffer, sizeof(iw_range)); // Fetch the stats wrq.u.data.pointer = (caddr_t) &stats; wrq.u.data.length = 0; wrq.u.data.flags = 1; /* Clear updated flag */ strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIWSTATS, &wrq) < 0) { snprintf(in_err, STATUS_MAX, "Failed to fetch signal stats, %s", strerror(errno)); close(skfd); return -1; } /* if (stats.qual.level <= range.max_qual.level) { *level = 0; *noise = 0; close(skfd); return 0; } */ *level = stats.qual.level - 0x100; *noise = stats.qual.noise - 0x100; close(skfd); return 0; } int Iwconfig_Get_Channel(const char *in_dev, char *in_err) { struct iwreq wrq; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(in_err, STATUS_MAX, "Failed to create AF_INET DGRAM socket %d:%s", errno, strerror(errno)); return -1; } memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIWFREQ, &wrq) < 0) { snprintf(in_err, STATUS_MAX, "channel get ioctl failed %d:%s", errno, strerror(errno)); close(skfd); return -1; } close(skfd); return (FloatChan2Int(IwFreq2Float(&wrq))); } int Iwconfig_Set_Channel(const char *in_dev, int in_ch, char *in_err) { struct iwreq wrq; int skfd; int ret = 0; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(in_err, STATUS_MAX, "Failed to create AF_INET DGRAM socket %d:%s", errno, strerror(errno)); return -1; } // Set a channel memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); #ifdef HAVE_LINUX_IWFREQFLAG wrq.u.freq.flags = IW_FREQ_FIXED; #endif if (in_ch > 1024) IwFloat2Freq(in_ch * 1e6, &wrq.u.freq); else IwFloat2Freq(in_ch, &wrq.u.freq); // Try twice with a tiny delay, some cards (madwifi) need a second chance... if (ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) { struct timeval tm; tm.tv_sec = 0; tm.tv_usec = 5000; select(0, NULL, NULL, NULL, &tm); if (ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) { if (errno == ENODEV) { ret = -2; } else { ret = -1; } snprintf(in_err, STATUS_MAX, "%s", strerror(errno)); close(skfd); return ret; } } close(skfd); return 0; } int Iwconfig_Get_Mode(const char *in_dev, char *in_err, int *in_mode) { struct iwreq wrq; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(in_err, STATUS_MAX, "Failed to create AF_INET DGRAM socket %d:%s", errno, strerror(errno)); return -1; } memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIWMODE, &wrq) < 0) { snprintf(in_err, STATUS_MAX, "mode get ioctl failed %d:%s", errno, strerror(errno)); close(skfd); return -1; } (*in_mode) = wrq.u.mode; close(skfd); return 0; } int Iwconfig_Set_Mode(const char *in_dev, char *in_err, int in_mode) { struct iwreq wrq; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(in_err, STATUS_MAX, "Failed to create AF_INET DGRAM socket %d:%s", errno, strerror(errno)); return -1; } memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, in_dev, IFNAMSIZ); wrq.u.mode = in_mode; if (ioctl(skfd, SIOCSIWMODE, &wrq) < 0) { snprintf(in_err, STATUS_MAX, "mode set ioctl failed %d:%s", errno, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } /* straight from wireless-tools; range struct definitions */ #define IW15_MAX_FREQUENCIES 16 #define IW15_MAX_BITRATES 8 #define IW15_MAX_TXPOWER 8 #define IW15_MAX_ENCODING_SIZES 8 #define IW15_MAX_SPY 8 #define IW15_MAX_AP 8 struct iw15_range { uint32_t throughput; uint32_t min_nwid; uint32_t max_nwid; uint16_t num_channels; uint8_t num_frequency; struct iw_freq freq[IW15_MAX_FREQUENCIES]; int32_t sensitivity; struct iw_quality max_qual; uint8_t num_bitrates; int32_t bitrate[IW15_MAX_BITRATES]; int32_t min_rts; int32_t max_rts; int32_t min_frag; int32_t max_frag; int32_t min_pmp; int32_t max_pmp; int32_t min_pmt; int32_t max_pmt; uint16_t pmp_flags; uint16_t pmt_flags; uint16_t pm_capa; uint16_t encoding_size[IW15_MAX_ENCODING_SIZES]; uint8_t num_encoding_sizes; uint8_t max_encoding_tokens; uint16_t txpower_capa; uint8_t num_txpower; int32_t txpower[IW15_MAX_TXPOWER]; uint8_t we_version_compiled; uint8_t we_version_source; uint16_t retry_capa; uint16_t retry_flags; uint16_t r_time_flags; int32_t min_retry; int32_t max_retry; int32_t min_r_time; int32_t max_r_time; struct iw_quality avg_qual; }; union iw_range_raw { struct iw15_range range15; /* WE 9->15 */ struct iw_range range; /* WE 16->current */ }; /* * Offsets in iw_range struct */ #define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \ (char *) NULL) #define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \ (char *) NULL) /* Get hw supported channels; rewritten from wireless-tools by Jean Tourilhes */ int Iwconfig_Get_Chanlist(const char *interface, char *errstr, vector *chan_list) { struct iwreq wrq; int skfd; char buffer[sizeof(struct iw_range) * 2]; union iw_range_raw *range_raw; struct iw_range range; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "%s: failed to create ioctl socket on %s: %s", __FUNCTION__, interface, strerror(errno)); return -1; } bzero(buffer, sizeof(buffer)); memset(&wrq, 0, sizeof(struct iwreq)); wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = sizeof(buffer); wrq.u.data.flags = 0; strncpy(wrq.ifr_name, interface, IFNAMSIZ); if (ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) { snprintf(errstr, STATUS_MAX, "%s: Failed to get frequency range on %s: %s", __FUNCTION__, interface, strerror(errno)); close(skfd); return -1; } range_raw = (union iw_range_raw *) buffer; /* Magic number to detect old versions */ /* For new versions, we can check the version directly, for old versions * we use magic. 300 bytes is a also magic number, don't touch... */ if (wrq.u.data.length < 300) { snprintf(errstr, STATUS_MAX, "Interface %s using wireless extensions which " "are too old to extract the supported channels list", interface); close(skfd); return -1; } /* Direct copy from wireless-tools; mangle the range code and * figure out what we need to do with it */ if (range_raw->range.we_version_compiled > 15) { memcpy((char *) &range, buffer, sizeof(iw_range)); } else { /* Zero unknown fields */ bzero((char *) &range, sizeof(struct iw_range)); /* Initial part unmoved */ memcpy((char *) &range, buffer, iwr15_off(num_channels)); /* Frequencies pushed futher down towards the end */ memcpy((char *) &range + iwr_off(num_channels), buffer + iwr15_off(num_channels), iwr15_off(sensitivity) - iwr15_off(num_channels)); /* This one moved up */ memcpy((char *) &range + iwr_off(sensitivity), buffer + iwr15_off(sensitivity), iwr15_off(num_bitrates) - iwr15_off(sensitivity)); /* This one goes after avg_qual */ memcpy((char *) &range + iwr_off(num_bitrates), buffer + iwr15_off(num_bitrates), iwr15_off(min_rts) - iwr15_off(num_bitrates)); /* Number of bitrates has changed, put it after */ memcpy((char *) &range + iwr_off(min_rts), buffer + iwr15_off(min_rts), iwr15_off(txpower_capa) - iwr15_off(min_rts)); /* Added encoding_login_index, put it after */ memcpy((char *) &range + iwr_off(txpower_capa), buffer + iwr15_off(txpower_capa), iwr15_off(txpower) - iwr15_off(txpower_capa)); /* Hum... That's an unexpected glitch. Bummer. */ memcpy((char *) &range + iwr_off(txpower), buffer + iwr15_off(txpower), iwr15_off(avg_qual) - iwr15_off(txpower)); /* Avg qual moved up next to max_qual */ memcpy((char *) &range + iwr_off(avg_qual), buffer + iwr15_off(avg_qual), sizeof(struct iw_quality)); } if (range.we_version_compiled <= 10) { snprintf(errstr, STATUS_MAX, "Interface %s using wireless extensions which " "are too old to extract the supported channels list", interface); close(skfd); return -1; } if (range.we_version_compiled > WE_MAX_VERSION) { snprintf(errstr, STATUS_MAX, "Interface %s using wireless extensions from " "the future; Recompile Kismet with your new kernel before Skynet " "takes over", interface); close(skfd); return -1; } if (range.num_frequency > 0) { /* Print them all */ for (int k = 0; k < range.num_frequency; k++) { int freq = (((double) range.freq[k].m) * pow(10, range.freq[k].e)) / 1000000; if (freq == 0) continue; chan_list->push_back(FreqToChan(freq)); } } close(skfd); return chan_list->size(); } #endif #endif // wireless kismet-2013-03-R1b/configure.in0000664000175000017500000010152212124602454015765 0ustar dragorndragorn# Process this file with autoconf to produce a configure script. AC_INIT AC_CONFIG_SRCDIR([kismet.h]) AC_PREREQ(2.57) # Check for host type AC_CANONICAL_HOST # Checks for programs. AC_PROG_CC AC_PROG_CXX AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_CPP # Liberated from ethereal's configure.in # # Add any platform-specific compiler flags needed. # AC_MSG_CHECKING(for platform-specific compiler flags) if test "x$GCC" = x then # # Not GCC - assume it's the vendor's compiler. # case "$host_os" in hpux*) # # HP's ANSI C compiler; flags suggested by Jost Martin. # "-Ae" for ANSI C plus extensions such as "long long". # "+O2", for optimization. XXX - works with "-g"? # CFLAGS="-Ae +O2 $CFLAGS" AC_MSG_RESULT(HP ANSI C compiler - added -Ae +O2) ;; darwin10*) # Snow leopard and newer, no -bundle in plugins CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' AC_MSG_RESULT(Apple OSX Snow Leopard or newer) AC_DEFINE(SYS_DARWIN, 1, Compiling for OSX/Darwin) darwin="yes" ;; darwin*) # # It may be called "cc", but it's really a GCC derivative # with a problematic special precompiler and precompiled # headers; turn off the special precompiler, as some # apparently-legal code won't compile with its precompiled # headers. # CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-bundle -flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' AC_MSG_RESULT(Apple GCC - added Apple80211 frameworks and no-precomp) AC_DEFINE(SYS_DARWIN, 1, Compiling for OSX/Darwin) darwin="yes" ;; linux*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_LINUX, 1, Compiling for Linux OS) linux="yes" ;; freebsd*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_FREEBSD, 1, Compiling for FreeBSD) bsd="yes" ;; openbsd*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_OPENBSD, 1, Compiling for OpenBSD) bsd="yes" ;; netbsd*) AC_MSG_RESULT(adding pkgsrc locations) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib" AC_DEFINE(SYS_NETBSD, 1, Compiling for NetBSD) bsd="yes" ;; cygwin*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_CYGWIN, 1, Compiling for Cygwin) cygwin="yes" ;; *) AC_MSG_RESULT(none needed) ;; esac else case "$host_os" in solaris*) # the X11 headers don't automatically include prototype info # and a lot don't include the return type CFLAGS="$CFLAGS -Wno-return-type -DFUNCPROTO=15" AC_MSG_RESULT(GCC on Solaris - added -Wno-return-type -DFUNCPROTO=15) ;; darwin10*) # Snow leopard and newer, no -bundle in plugins CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' AC_MSG_RESULT(Apple OSX Snow Leopard or newer) AC_DEFINE(SYS_DARWIN, 1, Compiling for OSX/Darwin) darwin="yes" ;; darwin*) # # See comments above about Apple's lovely C compiler. # CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" objc_link='$(OBJC_CONTROL_O)' PLUGINLDFLAGS="-bundle -flat_namespace -undefined suppress" AC_MSG_RESULT(Apple GCC - added Apple80211 frameworks and no-precomp) AC_DEFINE(SYS_DARWIN, 1, Compiling for OSX/Darwin) darwin="yes" ;; linux*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_LINUX, 1, Compiling for Linux OS) linux="yes" ;; freebsd*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_FREEBSD, 1, Compiling for FreeBSD) bsd="yes" ;; openbsd*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_OPENBSD, 1, Compiling for OpenBSD) bsd="yes" ;; netbsd*) AC_MSG_RESULT(adding pkgsrc locations) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib" AC_DEFINE(SYS_NETBSD, 1, Compiling for NetBSD) bsd="yes" ;; cygwin*) AC_MSG_RESULT(none needed) AC_DEFINE(SYS_CYGWIN, 1, Compiling for Cygwin) cygwin="yes" ;; *) AC_MSG_RESULT(none needed) ;; esac fi # Substitute in the objc linkages if we need them AC_SUBST(PLUGINLDFLAGS) AC_SUBST(objc_link) if test "$cygwin" = "yes"; then AC_MSG_CHECKING(cygwin compile flags) AC_MSG_RESULT(__MINGW32__) CXXFLAGS="$CXXFLAGS -D__MINGW32__" else # cygwin doesn't like rdynamic, will this hurt us? LDFLAGS="$LDFLAGS -rdynamic" fi AC_CONFIG_SRCDIR([kismet_server.cc]) AC_CONFIG_HEADER([config.h]) # Config location for code to default to CONFFILE_DIR=$sysconfdir CONFFILE_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$CONFFILE_DIR" )` AC_DEFINE_UNQUOTED(SYSCONF_LOC, "$CONFFILE_DIR", system config directory) LOCALSTATE_DIR=$localstatedir LOCALSTATE_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$LOCALSTATE_DIR" )` AC_DEFINE_UNQUOTED(LOCALSTATE_DIR, "$LOCALSTATE_DIR", system state directory) BIN_DIR=$bindir BIN_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$BIN_DIR" )` AC_DEFINE_UNQUOTED(BIN_LOC, "$BIN_DIR", system binary directory) LIB_DIR=$libdir LIB_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$LIB_DIR" )` AC_DEFINE_UNQUOTED(LIB_LOC, "$LIB_DIR", system library directory) DATA_DIR=$datarootdir DATA_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$DATA_DIR" )` AC_DEFINE_UNQUOTED(DATA_LOC, "$DATA_DIR", system data directory) # Check for endian AC_C_BIGENDIAN # Checks for header files. AC_CHECK_HEADERS([errno.h stdlib.h string.h sys/socket.h sys/time.h sys/wait.h unistd.h sys/types.h netdb.h], AC_DEFINE(HAVE_SYSHEADERS, 1, System headers are there), AC_MSG_ERROR(Missing required system header)) AC_CHECK_HEADERS([getopt.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME AC_STRUCT_TM # Checks for library functions. AC_HEADER_STDC AC_TYPE_SIGNAL AC_FUNC_STAT AC_CHECK_FUNCS([gettimeofday memset select socket strcasecmp strftime strstr]) # Do we have getopt_long natively? AC_MSG_CHECKING([for system-level getopt_long()]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #ifdef HAVE_GETOPT_H #include #endif ]], [[ static struct option long_options[] = { /* options table */ { "null-arg", required_argument, 0, 'n' }, { 0, 0, 0, 0 } }; int s; int option_index; int argc; char **argv; s = getopt_long(argc, argv, "n:", long_options, &option_index); ]])],[sys_getopt=yes],[sys_getopt=no]) if test "$sys_getopt" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_GETOPT_LONG, 1, system defines getopt_long) else AC_MSG_RESULT([no]) fi # Look for something to define standard int types stdint=yes AC_CHECK_HEADER([stdint.h], AC_DEFINE(HAVE_STDINT_H, 1, stdint.h is present) stdint=yes, stdint=no) if test "$stdint" = "no"; then inttypes=no AC_CHECK_HEADER([inttypes.h], AC_DEFINE(HAVE_INTTYPES_H, 1, inttypes.h is present) inttypes=yes, inttypes=no) fi if test "$stdint" = "no"; then if test "$inttypes" = "no"; then AC_MSG_RESULT([failed]) AC_MSG_ERROR(could not find stdint.h or inttypes.h.) fi fi # How does accept() work on this system? AC_MSG_CHECKING([for accept() addrlen type]) OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ int s = 0; struct sockaddr *addr = NULL; socklen_t *addrlen = NULL; accept(s, addr, addrlen); return 0; ]])],[accept_socklen=yes],[accept_socklen=no]) if test "$accept_socklen" = "yes"; then AC_MSG_RESULT([socklen_t]) AC_DEFINE(HAVE_SOCKLEN_T, 1, accept() takes type socklen_t for addrlen) else AC_MSG_RESULT([int]) fi CFLAGS="$OCFL" # Do we have large file support? AC_SYS_LARGEFILE # Do we need to use -ldl? usedl=0 AC_CHECK_LIB([dl], [dlopen], usedl=1, AC_MSG_WARN([libdl doesn't seem to be needed on this system])) if test "$usedl" -eq 1; then LIBS="$LIBS -ldl" CLIENTCLIBS="$CLIENTCLIBS -ldl" fi # sqlite3=yes # AC_CHECK_HEADER([sqlite3.h], # AC_DEFINE(HAVE_SQLITE_H, 1, sqlite3.h is present) sqlite3=yes, # sqlite3=no) # # if test "$sqlite3" = yes; then # AC_CHECK_LIB([sqlite3], [sqlite3_open], # KSLIBS="$KSLIBS -lsqlite3", sqlite3=no) # fi # # if test "$sqlite3" != yes; then # AC_MSG_WARN(Failed to find sqlite3 runtime resuming will be disabled) # fi # Do we need libm for math functions? AC_MSG_CHECKING([for libm math function in std libs]) OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ double x; pow(x, x); return 0; ]])],[needlibm=no],[needlibm=yes]) CFLAGS="$OCFL" if test "$needlibm" = "yes"; then AC_MSG_RESULT([no]) # Do we need to use -lm? AC_CHECK_LIB([m], [pow], LIBS="$LIBS -lm", AC_MSG_ERROR([libm is needed and is not available])) else AC_MSG_RESULT([yes]) fi # Do we use libstdc++? # We need to swap to the g++ compiler here oCC="$CC" CC="$CXX" AC_CHECK_LIB([uClibc++], [main], foundcxxl="uclibc" CXXLIBS="$CXXLIBS -luClibc++") # Do we use uclibc++? if test "$foundcxxl"x == "x"; then AC_CHECK_LIB([stdc++], [main], foundcxxl="stdc++" CXXLIBS="$CXXLIBS -lstdc++") fi if test "$foundcxxl"x == "x"; then AC_MSG_ERROR(Neither uclibc uClibc++ or standard gcc stdc++ libraries found.) fi CC="$oCC" AC_SUBST(CXXLIBS) AC_MSG_CHECKING([for group 'root']) if test "`grep -e ^root: /etc/group`" = ""; then AC_MSG_RESULT([no. Using 'wheel']) instgrp="wheel" else AC_MSG_RESULT([yes]) instgrp="root" fi AC_SUBST(instgrp) AC_MSG_CHECKING([for group 'man']) if test "`grep -e ^man: /etc/group`" = ""; then AC_MSG_RESULT([no. Using '$instgrp']) mangrp="$instgrp" else mangrp="man" fi AC_SUBST(mangrp) # Check for libcurses or libncurses. Fatal error if we didn't use disable. AC_ARG_ENABLE(client, [ --disable-client disable kismet client], [case "${enableval}" in no) wantclient=no ;; *) wantclient=yes ;; esac], [wantclient=yes] ) AC_SUBST(wantclient) # Add additional cflags since some distros bury panel.h CPPFLAGS="$CPPFLAGS -I/usr/include/ncurses" termcontrol="none"; if test "$wantclient" = "yes"; then OLIBS="$LIBS" AC_CHECK_LIB([ncurses], [initscr], AC_DEFINE(HAVE_LIBNCURSES, 1, NCurses terminal lib) \ foundlcurses=yes curseaux="-lncurses" termcontrol="ncurses" ) if test "$foundlcurses" != "yes"; then AC_CHECK_LIB([curses], [initscr], AC_DEFINE(HAVE_LIBCURSES, 1, Curses terminal lib) \ foundlcurses=yes curseaux="-lcurses" termcontrol="curses" ) fi if test "$foundlcurses" != "yes"; then AC_MSG_ERROR(Failed to find libcurses or libncurses. Install them or disable building the Kismet client with --disable-client. Disabling the client is probably not something you want to do normally.) fi if test "$termcontrol" = "ncurses"; then AC_CHECK_HEADER([ncurses.h], [foundhcurses=yes]) else AC_CHECK_HEADER([curses.h], [foundhcurses=yes]) fi if test "$foundhcurses" != "yes"; then AC_MSG_ERROR(Failed to find curses.h or ncurses.h. You probably need to install the curses-devel package from your distribution) fi LIBS="$LIBS $curseaux" AC_CHECK_LIB([panel], [new_panel], AC_DEFINE(HAVE_LIBPANEL, 1, Panel terminal lib) curseaux="$curseaux -lpanel", AC_MSG_ERROR(Failed to find libpanel extension to curses/ncurses. Install it, or disable building the Kismet client with --disable-client. Disabling the client is probably not something you want to do normally.)) AC_CHECK_HEADER([panel.h], [foundhpanel=yes]) if test "$foundhpanel" != "yes"; then AC_MSG_ERROR(Failed to find panel.h curses extension header. You probably need to install the curses-devel or panel-devel package from your distribution.) fi LIBS="$OLIBS" CLIENTCLIBS="$CLIENTCLIBS $curseaux" fi AC_SUBST(CLIBS) AC_SUBST(CLIENTCLIBS) AC_SUBST(CLIENTCFLAGS) # TODO - check for advanced curses stuff here like cdk/panels # Check for process title manipulation stuff, from proftpd configure.in AC_CHECK_FUNCS(setproctitle) AC_CHECK_HEADERS(libutil.h) AC_CHECK_LIB(util, setproctitle, [AC_DEFINE(HAVE_SETPROCTITLE) ac_cv_func_setproctitle="yes" ; LIBS="$LIBS -lutil"]) if test "$ac_cv_func_setproctitle" = "yes"; then AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_NONE) else pf_argv_set="no" AC_CHECK_HEADERS(sys/pstat.h,have_pstat_h="yes",have_pstat_h="no") if test "$have_pstat_h" = "yes"; then AC_CHECK_FUNCS(pstat) if test "$ac_cv_func_pstat" = "yes"; then AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_PSTAT, pstat argv type) else AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_WRITEABLE, writeable argv type) fi pf_argv_set="yes" fi if test "$pf_argv_set" = "no"; then AC_EGREP_HEADER([#define.*PS_STRINGS.*],sys/exec.h, have_psstrings="yes",have_psstrings="no") if test "$have_psstrings" = "yes"; then AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_PSSTRINGS) pf_argv_set="yes" fi fi if test "$pf_argv_set" = "no"; then AC_CACHE_CHECK(whether __progname and __progname_full are available, pf_cv_var_progname, AC_TRY_LINK([extern char *__progname, *__progname_full;], [__progname = "foo"; __progname_full = "foo bar";], pf_cv_var_progname="yes", pf_cv_var_progname="no")) if test "$pf_cv_var_progname" = "yes"; then AC_DEFINE(HAVE___PROGNAME, 1, __PROGNAME glibc macro available) fi AC_CACHE_CHECK(which argv replacement method to use, pf_cv_argv_type, AC_EGREP_CPP(yes,[ #if defined(__GNU_HURD__) yes #endif ],pf_cv_argv_type="new", pf_cv_argv_type="writeable")) if test "$pf_cv_argv_type" = "new"; then AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_NEW, new argv type) pf_argv_set="yes" fi if test "$pf_argv_set" = "no"; then AC_DEFINE(PF_ARGV_TYPE, PF_ARGV_WRITEABLE, writeable argv type) fi fi fi # Check for linux headers if we're on linux systems if test "$linux" = "yes"; then AC_ARG_WITH(linuxheaders, [ --with-linuxheaders[=DIR] Custom location of the Linux kernel headers if the glibc copies are insufficient ], [ if test "$withval" != no -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval" fi ]) AC_ARG_ENABLE(linuxwext, [ --disable-linuxwext disable Linux wireless extensions], [case "${enableval}" in no) wantwext=no ;; *) wantwext=yes ;; esac], [wantwext=yes] ) linux_wireless="no" if test "$wantwext" = "yes"; then AC_CHECK_HEADER([linux/wireless.h], [foundwexth=yes],, [ #include #include #include #include #include ]) if test "$foundwexth" != "yes"; then AC_MSG_ERROR(Failed to find a usable linux/wireless.h header for Linux Wireless Extensions. Either your kernel headers are missing or are incorrect. See config.log for the exact error. Compiling without wireless headers must be explicitly disabled) fi AC_MSG_CHECKING(that linux/wireless.h is what we expect) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include #include #include #include #include ]], [[ struct iwreq wrq; wrq.u.essid.flags = 0; ]])],[foundwextok=yes]) if test "$foundwextok" != "yes"; then AC_MSG_RESULT(no) AC_MSG_ERROR(Failed to find a usable linux/wireless.h header for Linux Wireless Extensions. Either your kernel headers are missing or are incorrect. See config.log for the exact error.) fi # wexth AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_WIRELESS, 1, Linux wireless extentions present) linux_wireless="yes"; if test "$linux_wireless" = "yes"; then iwfreqflag=no AC_MSG_CHECKING(can we use iw_freq.flags) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include #include #include ]], [[ struct iwreq wrq; wrq.u.freq.flags = IW_FREQ_FIXED; ]])],[iwfreqflag=yes],[iwfreqflag=no]) if test "$iwfreqflag" = "no"; then AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_IWFREQFLAG, 1, [Linux wireless iwfreq.flag]) fi fi fi # want headers fi # linux # Look for libgps # havelgps="yes" # AC_CHECK_LIB([gps], [gps_open],,havelgps=no) # AC_CHECK_HEADER([gps.h],,havelgps=no) # # if test "$havelgps" = "yes"; then # AC_DEFINE(HAVE_LIBGPS, 1, gpsd libgps client support) # KSLIBS="$KSLIBS -lgps" # fi # Look for capability support havecap="yes" AC_CHECK_LIB([cap], [cap_init],,havecap=no) AC_CHECK_HEADER([sys/prctl.h],, havecap=no) AC_CHECK_HEADER([sys/capability.h],, havecap=no) if test "$havecap" = "yes"; then AC_DEFINE(HAVE_CAPABILITY, 1, kernel capability support) caplibs="-lcap" AC_SUBST(caplibs) fi AC_ARG_WITH(pcreheaders, [ --with-pcreheaders[=DIR] Custom location of the PCRE library headers ], [ if test "$withval" != no -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval" fi ]) AC_ARG_ENABLE(pcre, [ --disable-pcre disable building pcre components], [case "${enableval}" in no) wantpcre=no ;; *) wantpcre=yes ;; esac], [wantpcre=yes] ) if test "$wantpcre" = "yes"; then # Check for pcre pcrel=no AC_CHECK_LIB([pcre], [pcre_compile], pcrel=yes, pcrel=no) if test "$pcrel" != "yes"; then AC_MSG_WARN(Failed to find libpcre) wantpcre=no fi if test "$wantpcre" = "yes"; then pcreh=no AC_CHECK_HEADER([pcre.h], pcreh=yes, pcreh=no) if test "$pcreh" != "yes"; then AC_MSG_WARN(Failed to find pcre headers check that the pcre-devel package is installed if your distribution provides separate packages) wantpcre=no fi fi # wantpcre if test "$wantpcre" = "yes"; then AC_DEFINE(HAVE_LIBPCRE, 1, libpcre regex support) LIBS="$LIBS -lpcre" fi # pcre fi # Handle airpcap/winpcap on cygwin if test "$cygwin" = yes; then AC_CHECK_HEADERS([windows.h Win32-Extensions.h]) AC_ARG_ENABLE(airpcap, [ --enable-airpcap enable checking for CACE airpcap], [case "${enableval}" in yes) want_airpcap=yes ;; *) want_airpcap=no ;; esac], [want_airpcap=yes] ) if test "$want_airpcap" = "yes"; then airpcap_devpack="Airpcap_Devpack" AC_ARG_WITH(airpcap-devpack, [ --with-airpcap[=DIR] Location of the CACE AirPcap device pack NOTE cygwin appears to have link errors if the path is not within the current directory], [ airpcap_devpack="$withval" ]) # Set the libs and includes LDFLAGS="$LDFLAGS -L$airpcap_devpack/Lib" CPPFLAGS="$CPPFLAGS -I$airpcap_devpack/Include" fi # want_airpcap winpcap_devpack="Winpcap_Devpack" AC_ARG_WITH(winpcap-devpack, [ --with-winpcap[=DIR] Location of the WinPcap device pack NOTE cygwin appears to have link errors if the path is not within the current directory], [ winpcap_devpack="$withval" ]) # Set the libs and includes LDFLAGS="$LDFLAGS -L$winpcap_devpack/Lib" CPPFLAGS="$CPPFLAGS -I$winpcap_devpack/Include" fi # cygwin AC_ARG_ENABLE(pcap, [ --disable-pcap disable libpcap (most sources) capture support], [case "${enableval}" in no) wantpcap=no ;; *) wantpcap=yes ;; esac], [wantpcap=yes] ) AC_SUBST(wantpcap) if test "$wantpcap" = yes; then foundsyspcap=no if test "$cygwin" = yes; then pcaplib="wpcap"; else pcaplib="pcap"; fi AC_CHECK_LIB([${pcaplib}], [pcap_open_live], AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib) foundsyspcap=yes, AC_MSG_WARN(Compiling without libpcap support.)) if test "$foundsyspcap" = yes; then ## if we don't have a pcap.h, do a search for pcap/pcap.h AC_CHECK_HEADER([pcap.h], AC_DEFINE(HAVE_PCAP_H, 1, libpcap header) foundsyspcaph=yes) if test "$foundsyspcaph" != yes; then AC_CHECK_HEADER([pcap/pcap.h], AC_DEFINE(HAVE_PCAP_H, 1, libpcap header) AC_DEFINE(HAVE_PCAPPCAP_H, 1, pcap/pcap.h), AC_MSG_ERROR([found libpcap but unable to find pcap.h])) fi # Look for the new PCAP stuff AC_CHECK_LIB([pcap], [pcap_setnonblock], AC_DEFINE(HAVE_PCAP_NONBLOCK, 1, Nonblocking-capable libpcap), AC_MSG_WARN(*** You don't appear to have a version of libpcap which supports non-blocking IO. We'll fake it, but you REALLY should upgrade your libpcap, as it may not support 802.11 capture sources, either. ***)) if test "$cygwin" != yes; then AC_CHECK_LIB([${pcaplib}], [pcap_get_selectable_fd], AC_DEFINE(HAVE_PCAP_GETSELFD, 1, Selectablefd-capable libpcap), AC_MSG_ERROR(installed libpcap version does not support features Kismet requires. Upgrade to a current version of libpcap)) else AC_CHECK_LIB([${pcaplib}], [pcap_fileno], AC_DEFINE(HAVE_PCAP_FILENO, 1, pcapfileno-capable libwpcap), AC_MSG_ERROR(installed libpcap version does not support features Kismet requires. Upgrade to a current version of libwpcap)) fi # Look for PPI support in pcap AC_MSG_CHECKING([for PPI support in libpcap]) OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ return DLT_PPI==DLT_PPI; ]])],[haveppi=yes],[haveppi=no]) CFLAGS="$OCFL" if test "$haveppi" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_PPI, 1, libpcap supports PPI) else AC_MSG_RESULT([no]) fi pcaplnk="-l${pcaplib}" AC_SUBST(pcaplnk) pcap="yes" fi fi if test "$wantpcap" = "yes" -a "$pcap" != "yes"; then AC_MSG_ERROR(Could not find working libpcap. Libpcap is vital for the majority of capture sources Kismet supports. It must be explicitly disabled.) fi if test "$wantpcap" != "yes" -o "$pcap" != "yes"; then AC_MSG_WARN(Compiling without libpcap support. Many capture sources will be disabled.) fi AC_SUBST(pcap) if test "$pcap" = "no" -a "$want_airpcap" = "yes"; then AC_MSG_WARN([*** Disabling AirPcap, libpcap not enabled ***]); want_airpcap=no; fi if test "$want_airpcap" = "yes" -a "$pcap" = "yes"; then foundairpcap=no AC_CHECK_LIB([airpcap], [AirpcapSetLinkType], AC_DEFINE(HAVE_LIBAIRPCAP, 1, libairpcap win32 control lib) foundairpcap=yes, AC_MSG_WARN(Compiling without airpcap support.)) if test "$foundairpcap" = yes; then ## if we don't have a pcap.h, do a search for pcap/pcap.h AC_CHECK_HEADER([airpcap.h], AC_DEFINE(HAVE_AIRPCAP_H, 1, libairpcap header) foundairpcaph=yes) fi if test "$foundairpcap" != "yes" -o "$foundairpcaph" != "yes"; then AC_MSG_WARN(Compiling without airpcap support) else airpcap="yes" KSLIBS="$KSLIBS -lairpcap" fi fi if test "$bsd" = yes; then AC_MSG_CHECKING(for BSD net80211/radiotap support) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include #include #include ]], [[ ]])],radiotap=yes bsdradiotap=yes, bsdradiotap=no radiotap=no) AC_MSG_RESULT($bsdradiotap) else AC_MSG_WARN(Using local radiotap headers) fi if test "$radiotap" != "yes"; then AC_DEFINE(HAVE_LOCAL_RADIOTAP, 1, local radiotap packet headers) radiotaploc="local" fi if test "$bsdradiotap" = "yes"; then AC_DEFINE(HAVE_BSD_SYS_RADIOTAP, 1, BSD radiotap packet headers) radiotaploc="system (BSD)" fi # havenetlink=no if test "$linux" = "yes"; then # havenetlink=yes # AC_CHECK_HEADERS([asm/types.h netlink/genl/genl.h netlink/genl/family.h netlink/genl/ctrl.h netlink/msg.h netlink/attr.h linux/nl80211.h linux/if_arp.h linux/wireless.h], # AC_DEFINE(HAVE_NETLINKHEADERS, 1, Netlink headers are there), # havenetlink=no, # [#include ]) havenetlink=yes #if test "$havenetlink" = "yes"; then # AC_CHECK_LIB([nl], [nl_handle_alloc], # AC_DEFINE(HAVE_LIBNL, 1, libnl netlink library), havenetlink=no) #else # AC_MSG_WARN(Missing libnl or libnl too old support will not be able to control mac80211 vaps) #fi netlink_force=no AC_ARG_WITH(netlink-version, [ --with-netlink-version[=1|2|3] Force using libnl1, libnl2, or libnl-3 ], [ netlink_force=$withval ]) AC_CHECK_PROG(havepkgconfig, [pkg-config], yes, no) if test "$havepkgconfig" = "no"; then AC_MSG_WARN(Missing pkg-config will lead to multiple other checks failing) fi NLLIBS="" NLCFLAGS="" nlname="" if test "$havenetlink" = "yes"; then PKG_CHECK_MODULES(libnl30, [libnl-3.0], libnl30=yes, libnl30=no) PKG_CHECK_MODULES(libnlgenl30, [libnl-genl-3.0], libnlgenl30=yes, libnlgenl30=no) PKG_CHECK_MODULES(libnl20, [libnl-2.0], libnl20=yes, libnl20=no) PKG_CHECK_MODULES(libnl1, [libnl-1], libnl1=yes, libnl1=no) picked_nl=no if test $picked_nl = "no" -a "$libnl30" = "yes" -a "$libnlgenl30" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "3"; then picked_nl=3 AC_DEFINE(HAVE_LIBNL, 1, libnl netlink library) AC_DEFINE(HAVE_LIBNL30, 1, libnl-3.0 netlink library) nlname="libnl-3.0 libnl-genl-3.0" fi fi if test $picked_nl = "no" -a "$libnl20" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "2"; then picked_nl=2 AC_DEFINE(HAVE_LIBNL, 1, libnl netlink library) AC_DEFINE(HAVE_LIBNL20, 1, libnl-2.0 netlink library) nlname="libnl-2.0" fi fi if test $picked_nl = "no" -a "$libnl1" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "1"; then picked_nl=1 AC_DEFINE(HAVE_LIBNL, 1, libnl netlink library) nlname="libnl-1" fi fi if test $picked_nl = "no"; then havenetlink="no" fi if test "$nlname" != ""; then NLLIBS=`pkg-config --libs $nlname` NLCFLAGS=`pkg-config --cflags $nlname` fi fi if test "$havenetlink" = "yes"; then OLIBS="$LIBS" LIBS="$LIBS $NLLIBS" OCFL="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $NLCFLAGS" AC_MSG_CHECKING(For mac80211 support in netlink library) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include #include #include #include #include #include #include ]], [[ NL80211_IFTYPE_MONITOR; NL80211_CMD_NEW_INTERFACE; return 0; ]])],[havenetlink=yes KSLIBS="$KSLIBS $NLLIBS"],[havenetlink=no]) LIBS="$OLIBS" else AC_MSG_WARN(Missing libnl netlink library will not be able to control mac80211 vaps) havenetlink=no fi if test "$havenetlink" = "yes"; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_NETLINK, 1, Netlink works) fi fi if test "$darwin" = "yes"; then suidgroup="staff" else suidgroup="kismet" fi AC_ARG_WITH(suidgroup, [ --with-suidgroup=group Group allowed to execute the kismet_capture suid root helper process ], [ if test "$withval"x != "x"; then suidgroup="$withval" fi ]) AC_SUBST(suidgroup) # Evaluate suid if test "$cygwin" = "yes"; then suid="no" fi # gpsmap checks # We include GPS handling code regardless, for now. AC_DEFINE(HAVE_GPS, 1, GPS support will be built.) AC_ARG_ENABLE(optimization, [ --disable-optimization disable -Ox gcc optimization], [case "${enableval}" in no) wantopto=no ;; *) wantopto=yes ;; esac], [wantopto=yes] ) if test "$wantopto" != "yes"; then CPPFLAGS=`echo $CPPFLAGS | sed -e 's/-O.//g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-O.//g'` fi AC_SUBST(threadlib) AC_SUBST(KSLIBS) sharedatadir=$datadir sharedatadir=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$sharedatadir" )` sharedatadir=${sharedatadir} AC_SUBST(sharedatadir) AC_CONFIG_FILES([Makefile Makefile.inc scripts/kismet conf/kismet.conf]) AC_OUTPUT echo echo "Configuration complete: " echo " Compiling for: $host_os ($host_cpu)" echo " C++ Library: $foundcxxl" echo " Installing as group: $instgrp" echo " Man pages owned by: $mangrp" echo " Installing into: $prefix" printf " Setuid group: " if test "$cygwin" = "yes"; then echo "n/a (Cygwin/Win32"; else echo "$suidgroup" fi printf " Terminal Control: " echo "$termcontrol"; printf " Linux WEXT capture : " if test "$linux_wireless" = "yes"; then echo "yes" elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no" fi printf " OSX/Darwin capture : " if test "$darwin" = "yes"; then echo "yes" elif test "$darwin" != "yes"; then echo "n/a (only OSX/Darwin)" else echo "no" fi printf " PCRE Regex Filters : " if test "$wantpcre" = "yes"; then echo "yes" else echo "no" fi printf " pcap capture: " if test "$pcap" = "yes"; then echo "yes" else echo "no" fi printf " airpcap control: " if test "$airpcap" = "yes"; then echo "yes" elif test "$cygwin" != "yes"; then echo "n/a (only Cygwin/Win32)" else echo "no" fi printf " PPI log format: " if test "$haveppi" = "yes"; then echo "yes" else echo "no - PPI logging unavailable, upgrade libpcap" fi printf "LibCapability (enhanced\n" printf " privilege dropping): " if test "$havecap" = "yes"; then echo "yes"; elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no"; fi printf " Linux Netlink: " if test "$havenetlink" = "yes"; then echo "yes (mac80211 VAP creation) - $nlname"; elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no (will not be able to make mac80211 vaps)"; fi # printf " GPSD LibGPS: " # if test "$havelgps" = "yes"; then # echo "yes (GPSD LibGPS client)"; # else # echo "no (Using Kismet GPSD interface for GPSD <= 2.90)"; # fi if test "$havepkgconfig" = "no"; then echo echo "pkg-config was missing. Without it, configure cannot detect " echo "several libraries Kismet needs. Install pkg-config and re-run" echo "configure." fi if test "`echo $host_os | grep linux`" = ""; then echo echo "Configuration complete. You are not running a linux-based system," echo "you will likely need to use 'gmake' instead of 'make'." echo "Run 'gmake dep' to generate dependencies and 'gmake' followed by" echo "'gmake install' to compile and install Kismet" else verminor=`uname -r | cut -d '.' -f 2` # Stupid redhat vertiny=`uname -r | cut -d '.' -f 3 | cut -f 1 -d-` echo echo "Configuration complete. Run 'make dep' to generate dependencies" echo "and 'make' followed by 'make install' to compile and install." fi if test "$linux_wireless" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "Linux Wireless Extensions were disabled. Compiling without wext on a " echo "Linux system is certainly possible, however nearly all of the packet " echo "sources will be disabled (including capture sources for Cisco, Madwifi, " echo "Orinoco, Prism, and just about every other live capture method). Make " echo "sure this is what you want to do." echo "*** WARNING ***" fi if test "$pcap" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "LibPCAP was not found." echo "Kismet on Linux without LibPcap cannot capture data locally and will " echo "almost certainly NOT BE WHAT YOU WANT." echo "You need both the libpcap libraries and development headers (called " echo "libpcap-dev or libpcap-devel by most distributions)." fi if test "$havenetlink" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "LibNL/nl80211 support was not found. Kismet uses libnl to control " echo "mac80211 based wireless interfaces, which comprise the vast majority of" echo "interfaces on modern Linux systems. Unless you plan to use only " echo "older drivers, you need libnl." echo "You need both the libnl libraries and development headers (called " echo "libnl-dev or libnl-devel by most distributions)." if test "$havepkgconfig" = "no"; then echo "You do not have the pkg-config utility installed. Kismet needs " echo "this to find the options libnl uses. If libnl is installed but " echo "pkg-config is not, Kismet will not detect libnl!" fi fi if test "$havenetlink" = "yes" -a "$pcap" = "yes"; then echo echo "*** WARNING ***" echo "In some situations, libpcap links to libnl. If Kismet finds a newer " echo "libbl, it can cause an immediate segfault when starting Kismet. " echo echo "It is very hard to test at compile time (and run-time changes can " echo "cause it to break). If you experience immediate segfaults when " echo "trying to start kismet_server, check your libpcap.so with 'ldd'" echo "and either install a libpcap which does not link libnl1, or " echo "force Kismet to compile with a degraded libnl via " echo "./configure --with-netlink-version=1" echo fi kismet-2013-03-R1b/kis_ppi.h0000664000175000017500000000751512124602454015272 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PPI_H__ #define __PPI_H__ #include "config.h" /* PPI flexible-header packet format */ #ifndef DLT_PPI #define DLT_PPI 192 /* cace PPI */ #endif // CACE PPI headers typedef struct { uint8_t pph_version; uint8_t pph_flags; uint16_t pph_len; uint32_t pph_dlt; } __attribute__((packed)) ppi_packet_header; #define PPI_PH_FLAG_ALIGNED 2 typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; } __attribute__((packed)) ppi_field_header; #define PPI_FIELD_11COMMON 2 #define PPI_FIELD_11NMAC 3 #define PPI_FIELD_11NMACPHY 4 #define PPI_FIELD_SPECMAP 5 #define PPI_FIELD_PROCINFO 6 #define PPI_FIELD_CAPINFO 7 #define PPI_FIELD_GPS 30002 typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; uint64_t tsf_timer; uint16_t flags; uint16_t rate; uint16_t freq_mhz; uint16_t chan_flags; uint8_t fhss_hopset; uint8_t fhss_pattern; int8_t signal_dbm; int8_t noise_dbm; } __attribute__((packed)) ppi_80211_common; typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; uint8_t version; uint8_t magic; uint16_t gps_len; uint32_t fields_present; uint8_t field_data[0]; } __attribute__((packed)) ppi_gps_hdr; #define PPI_GPS_MAGIC 0xCF #define PPI_GPS_FLAG_LON 2 #define PPI_GPS_FLAG_LAT 4 #define PPI_GPS_FLAG_ALT 8 #define PPI_GPS_FLAG_ALT_G 16 #define PPI_GPS_FLAG_GPSTIME 32 #define PPI_GPS_FLAG_FRACTIME 64 #define PPI_GPS_FLAG_EPH 128 #define PPI_GPS_FLAG_EPV 256 #define PPI_GPS_FLAG_EPT 512 #define PPI_GPS_FLAG_APPID 536870912 #define PPI_GPS_FLAG_DATA 1073741824 #define PPI_80211_FLAG_FCS 1 #define PPI_80211_FLAG_TSFMS 2 #define PPI_80211_FLAG_INVALFCS 4 #define PPI_80211_FLAG_PHYERROR 8 #define PPI_80211_CHFLAG_TURBO 16 #define PPI_80211_CHFLAG_CCK 32 #define PPI_80211_CHFLAG_OFDM 64 #define PPI_80211_CHFLAG_2GHZ 128 #define PPI_80211_CHFLAG_5GHZ 256 #define PPI_80211_CHFLAG_PASSIVE 512 #define PPI_80211_CHFLAG_DYNAMICCCK 1024 #define PPI_80211_CHFLAG_GFSK 2048 typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; uint32_t flags; uint32_t a_mpdu_id; uint8_t num_delimiters; uint8_t reserved[3]; } __attribute__((packed)) ppi_11n_mac; #define PPI_11NMAC_GREENFIELD 1 #define PPI_11NMAC_HT2040 2 #define PPI_11NMAC_RX_SGI 4 #define PPI_11NMAC_DUPERX 8 #define PPI_11NMAC_AGGREGATE 16 #define PPI_11NMAC_MOREAGGREGATE 32 #define PPI_11NMAC_AGGCRC 64 typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; uint32_t flags; uint32_t a_mpdu_id; uint8_t num_delimiters; uint8_t mcs; uint8_t num_streams; uint8_t combined_rssi; uint8_t ant0_ctl_rssi; uint8_t ant1_ctl_rssi; uint8_t ant2_ctl_rssi; uint8_t ant3_ctl_rssi; uint8_t ant0_ext_rssi; uint8_t ant1_ext_rssi; uint8_t ant2_ext_rssi; uint8_t ant3_ext_rssi; uint16_t extension_freq_mhz; uint16_t extension_flags; int8_t ant0_signal_dbm; int8_t ant0_noise_dbm; int8_t ant1_signal_dbm; int8_t ant1_noise_dbm; int8_t ant2_signal_dbm; int8_t ant2_noise_dbm; int8_t ant3_signal_dbm; int8_t ant3_noise_dbm; uint32_t evm0; uint32_t evm1; uint32_t evm2; uint32_t evm3; } __attribute__((packed)) ppi_11n_macphy; #endif kismet-2013-03-R1b/stamp-h.in0000664000175000017500000000000012124602454015342 0ustar dragorndragornkismet-2013-03-R1b/battery.cc0000664000175000017500000002231312124602454015435 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #if defined(SYS_OPENBSD) && defined(HAVE_MACHINE_APMVAR_H) #include #endif #ifdef SYS_DARWIN #include #include #include #define LCDP_BATT_ABSENT 1 #define LCDP_AC_ON 2 #define LCDP_BATT_UNKNOWN 3 #define LCDP_AC_OFF 4 #define LCDP_BATT_CHARGING 5 #define LCDP_BATT_HIGH 6 #define LCDP_BATT_LOW 7 #define LCDP_BATT_CRITICAL 8 #endif #ifdef SYS_NETBSD #include #include #include #include #include #endif #include "battery.h" int Fetch_Battery_Info(kis_battery_info *out) { out->percentage = 0; out->charging = 0; out->remaining_sec = 0; out->ac = 1; #ifdef SYS_LINUX char buf[128]; FILE *bfile; char units[32]; if ((bfile = fopen("/proc/apm", "r")) != NULL) { int line_status, bat_status, flag, perc, apm_time; if (fgets(buf, 128, bfile) == NULL) { fclose(bfile); goto apmfail; } if (sscanf(buf, "%*s %*d.%*d %*x %x %x %x %d%% %d %32s\n", &line_status, &bat_status, &flag, &perc, &apm_time, units) != 6) { fclose(bfile); goto apmfail; } if ((flag & 0x80) == 0 && bat_status != 0xFF) { out->percentage = perc; } if (line_status == 1) out->ac = 1; else out->ac = 0; if (bat_status == 3) out->charging = 1; else out->charging = 0; if (apm_time < 0) out->remaining_sec = 0; else out->remaining_sec = apm_time; if (!strncmp(units, "min", 32)) out->remaining_sec *= 60; fclose(bfile); return 1; } // Fail to trying to read ACPI apmfail: DIR *adir; struct dirent *ent; int rate = 0, cap = 0, remain = 0, tint = 0; string bpath; adir = opendir("/proc/acpi/battery"); if (adir == NULL) { // No batteries, assume we're on AC out->percentage = 0; out->charging = 0; out->remaining_sec = 0; out->ac = 1; return 1; } while ((ent = readdir(adir)) != NULL) { bpath = "/proc/acpi/battery/" + string(ent->d_name) + "/state"; if ((bfile = fopen(bpath.c_str(), "r")) == NULL) continue; while (fgets(buf, 128, bfile)) { if (strlen(buf) < 26) continue; if (strstr(buf, "charging state:") == buf) { // Only reset charging if no batteries are charging if (strstr(buf + 25, "charged") == (buf + 25) && out->charging != 1) { out->charging = 2; } else if (strstr(buf + 25, "discharging") == (buf + 25)) { out->charging = 0; out->ac = 0; } else if (strstr(buf + 25, "charging") == (buf + 25)) { out->charging = 1; out->ac = 1; } } else if (strstr(buf, "present rate:") == buf) { // Add discharge rates across all batteries if (sscanf(buf + 25, "%d", &tint) == 1) { rate += tint; } } else if (strstr(buf, "remaining capacity:") == buf) { // Add remaining across all batteries if (sscanf(buf + 25, "%d", &tint) == 1) remain += tint; } } fclose(bfile); bpath = "/proc/acpi/battery/" + string(ent->d_name) + "/info"; if ((bfile = fopen(bpath.c_str(), "r")) == NULL) { continue; } while (fgets(buf, 128, bfile)) { if (strlen(buf) < 26) continue; // Add the last fulls if (strstr(buf, "last full capacity:") == buf) { if (sscanf(buf + 25, "%d", &tint) == 1) { cap += tint; } } } fclose(bfile); } closedir(adir); out->percentage = (float) ((float) remain / cap) * 100; if (rate > 0) out->remaining_sec = (float) ((float) remain / rate) * 60 * 60; #elif defined(SYS_DARWIN) // Battery handling code from Kevin Finisterre & Apple specs CFTypeRef blob = IOPSCopyPowerSourcesInfo(); CFArrayRef sources = IOPSCopyPowerSourcesList(blob); int i, bat_available = 0; CFDictionaryRef pSource = NULL; const void *psValue; int acstat = 0, battflag = LCDP_BATT_ABSENT; if (CFArrayGetCount(sources) != 0) { for (i = 0; i < CFArrayGetCount(sources); i++) { pSource = IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i)); if (pSource == NULL) break; psValue = (CFStringRef) CFDictionaryGetValue(pSource, CFSTR(kIOPSNameKey)); if (CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsPresentKey), &psValue) && (CFBooleanGetValue((CFBooleanRef) psValue))) { psValue = (CFStringRef) CFDictionaryGetValue(pSource, CFSTR(kIOPSPowerSourceStateKey)); if (CFStringCompare((CFStringRef) psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) { battflag = LCDP_BATT_UNKNOWN; acstat = LCDP_AC_OFF; out->charging = 0; } else if (CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue)) { if (CFBooleanGetValue((CFBooleanRef) psValue) > 0) { battflag = LCDP_BATT_CHARGING; out->charging = 1; } else { battflag = LCDP_BATT_UNKNOWN; } } if (battflag != LCDP_BATT_ABSENT) { int curCapacity = 0; int maxCapacity = 0; int remainingTime = 0; int timeToCharge = 0; bat_available = 1; psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSCurrentCapacityKey)); CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type, &curCapacity); psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSMaxCapacityKey)); CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type, &maxCapacity); out->percentage = (maxCapacity / curCapacity) * 100; // If this is 0 we are on AC, if it's a negative we are // "calculating", psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSTimeToEmptyKey)); CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type, &remainingTime); if (remainingTime == 0) out->ac = 1; else out->ac = 0; psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSTimeToFullChargeKey)); CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type, &timeToCharge); if (out->charging && timeToCharge > 0) { out->charging = 1; } else if (remainingTime > 0) { out->remaining_sec = remainingTime * 60; out->charging = 0; out->ac = 0; } } } } } #elif defined(SYS_OPENBSD) && defined(HAVE_MACHINE_APMVAR_H) struct apm_power_info api; int apmfd; if ((apmfd = open("/dev/apm", O_RDONLY)) < 0) { return 1; } else if (ioctl(apmfd, APM_IOC_GETPOWER, &api) < 0) { close(apmfd); return 1; } else { close(apmfd); switch(api.battery_state) { case APM_BATT_UNKNOWN: case APM_BATTERY_ABSENT: return 1; } out->percentage = (int) api.battery_life; out->remaining_sec = (int) api.minutes_left * 60; if (api.battery_state == APM_BATT_CHARGING) { out->ac = 1; out->charging = 1; } else { switch (api.ac_state) { case APM_AC_ON: out->ac = 1; if (bat_percentage < 100) { out->charging = 1; } else { out->charging = 0; } break; default: out->ac = 0; out->charging = 0; } } } #elif defined(SYS_NETBSD) static int fd = -1; int i; envsys_basic_info_t info; envsys_tre_data_t data; unsigned int charge = 0; unsigned int maxcharge = 0; unsigned int rate = 0; if (fd < 0 && (fd = open(_PATH_SYSMON, O_RDONLY)) < 0) return 1; for (i = 0; i >= 0; i++) { memset(&info, 0, sizeof(info)); info.sensor = i; if (ioctl(fd, ENVSYS_GTREINFO, &info) == -1) { close(fd); return 1; } if (!(info.validflags & ENVSYS_FVALID)) break; memset(&data, 0, sizeof(data)); data.sensor = i; if(ioctl(fd, ENVSYS_GTREDATA, &data) == -1) { close(fd); return 1; } if (!(data.validflags & ENVSYS_FVALID)) continue; if (strcmp("acpiacad0 connected", info.desc) == 0) { out->ac = data.cur.data_us; } else if (strcmp("acpibat0 charge", info.desc) == 0) { out->percentage = (unsigned int) ((data.cur.data_us * 100.0) / data.max.data_us); charge = data.cur.data_us; maxcharge = data.max.data_us; } else if (strcmp("acpibat0 charging", info.desc) == 0) { out->charging = data.cur.data_us > 0 ? 1 : 0; } else if (strcmp("acpibat0 discharge rate", info.desc) == 0) { rate = data.cur.data_us; } } if (out->charging != 0) out->remaining_sec = rate ? (unsigned int) ((maxcharge - charge) * 3600.0 / rate) : 0; else out->remaining_sec = rate ? (unsigned int) ((charge * 3600.0) / rate) : 0; #endif return 1; } kismet-2013-03-R1b/clinetframework.h0000664000175000017500000001265612124602454017032 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __CLINETFRAMEWORK_H__ #define __CLINETFRAMEWORK_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "messagebus.h" #include "timetracker.h" #include "globalregistry.h" #include "ringbuf.h" #include "pollable.h" // Basic superclass frameworks for network clients. Same basic sctructure // as the server framework // Forward prototypes class NetworkClient; class ClientFramework; #define CLIFRAME_FAIL_CB_PARMS GlobalRegistry *globalreg, int in_errno, void *auxptr typedef void (*cliframe_fail_cb)(CLIFRAME_FAIL_CB_PARMS); #define NETCLI_CONNECT_CB_PARMS GlobalRegistry *globalreg, int status, void *auxptr typedef void (*netcli_connect_cb)(NETCLI_CONNECT_CB_PARMS); // Skeleton for a network server class NetworkClient : public Pollable { public: NetworkClient(); NetworkClient(GlobalRegistry *in_globalreg); virtual ~NetworkClient(); // Register a client protocol framework virtual void RegisterClientFramework(ClientFramework *in_frm) { cliframework = in_frm; } // Is the client valid for any other ops? virtual int Valid() { return cl_valid; } // Core select loop merge - combine FDs with the master FD list, and // handle a strobe across pending FDs virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); // Flush all output buffers if we can virtual int FlushRings(); // Connect virtual int Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux) = 0; // Kill the connection virtual void KillConnection(); // Read, write, and mark are essentially fallthroughs directly to // the ringbuffers. We actually define these since it's // unlikely that they'd be drastically overridden // Write data virtual int WriteData(void *in_data, int in_len); // Amount of data pending in a client ring virtual int FetchReadLen(); // Read data virtual int ReadData(void *ret_data, int in_max, int *ret_len); // Mark data as read (ie, we've extracted it and parsed it) virtual int MarkRead(int in_readlen); protected: // Validate a connection virtual int Validate() = 0; // Read pending bytes from whereever into the ringbuffer virtual int ReadBytes() = 0; // Write pending bytes from the ringbuffer to whatever virtual int WriteBytes() = 0; netcli_connect_cb connect_cb; void *connect_aux; char errstr[STATUS_MAX]; int cl_valid; int cli_fd; int connect_complete; GlobalRegistry *globalreg; ClientFramework *cliframework; RingBuffer *read_buf; RingBuffer *write_buf; struct sockaddr_in client_sock, local_sock; struct hostent *client_host; }; // Skeleton to a protocol interface class ClientFramework : public Pollable { public: ClientFramework() { fprintf(stderr, "FATAL OOPS: ClientFramework called with no globalreg\n"); exit(1); }; ClientFramework(GlobalRegistry *in_reg) { globalreg = in_reg; netclient = NULL; fail_cb = NULL; fail_aux = NULL; globalreg->RegisterPollableSubsys(this); } virtual ~ClientFramework() { globalreg->RemovePollableSubsys(this); }; // Register the network server core that we use to talk out virtual void RegisterNetworkClient(NetworkClient *in_netc) { netclient = in_netc; } // Parse data virtual int ParseData() = 0; // Kill a connection virtual int KillConnection() { if (netclient != NULL && netclient->Valid()) { netclient->KillConnection(); } if (fail_cb != NULL) (*fail_cb)(globalreg, 0, fail_aux); return 1; } // Shutdown the protocol virtual int Shutdown(); // Is the connection valid? virtual int Valid() { if (netclient == NULL) return 0; return netclient->Valid(); } virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { if (netclient == NULL) return in_max_fd; return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set& in_rset, fd_set& in_wset) { if (netclient == NULL) return 0; return netclient->Poll(in_rset, in_wset); } virtual void RegisterFailCB(cliframe_fail_cb in_cb, void *in_aux) { fail_cb = in_cb; fail_aux = in_aux; } protected: cliframe_fail_cb fail_cb; void *fail_aux; char errstr[STATUS_MAX]; GlobalRegistry *globalreg; NetworkClient *netclient; }; #endif kismet-2013-03-R1b/kismet.spec0000664000175000017500000000321512124602454015624 0ustar dragorndragornSummary: Kismet is an 802.11 network sniffer and network dissector. Name: kismet Version: 2004.03 Release: 1 Group: Networking/Utilities Copyright: GPL Url: www.kismetwireless.net Source: kismet-%{version}.%{release}.tar.gz BuildRoot: %{_tmppath}/%{name}-root %description Kismet is an 802.11 layer2 wireless network detector, sniffer, and intrusion detection system. Kismet will work with any wireless card which supports raw monitoring (rfmon) mode, and can sniff 802.11b, 802.11a, and 802.11g traffic. %prep %setup -q %build %configure make %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT/ rpm #%clean #rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc README docs/DEVEL.* %config /etc/kismet.conf %config /etc/kismet_ui.conf %config /etc/kismet_drone.conf /etc/ap_manuf /etc/client_manuf /usr/bin/kismet /usr/bin/kismet_client /usr/bin/kismet_drone %attr(0755,root,root) /usr/bin/kismet_server %attr(0755,root,root) /usr/bin/kismet_drone /usr/share/kismet/wav/*.wav /usr/share/man/man1/gpsmap.1.gz /usr/share/man/man1/kismet.1.gz /usr/share/man/man1/kismet_drone.1.gz /usr/share/man/man5/kismet.conf.5.gz /usr/share/man/man5/kismet_ui.conf.5.gz /usr/share/man/man5/kismet_drone.conf.5.gz %changelog * Wed Aug 21 2002 Jeremiah Johnson - Initial specfile creation. * Sat Sep 21 2002 Mike Kershaw - Added manuf tag files, additional man files * Mon Feb 24 2002 Mike Kershaw - Added drone man files and kismet_drone binary * Sat Mar 13 2004 Mike Kershaw - Updated spec file (finally), removed suid install, updated other info kismet-2013-03-R1b/gpsserial.h0000664000175000017500000000314712124602454015622 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __GPSSERIAL_H__ #define __GPSSERIAL_H__ #include "config.h" #include "clinetframework.h" #include "serialclient.h" #include "kis_netframe.h" #include "packetchain.h" #include "gpscore.h" class GPSSerial : public GPSCore { public: GPSSerial(); GPSSerial(GlobalRegistry *in_globalreg); virtual ~GPSSerial(); virtual int Timer(); // Hooks so we can override straight to the TCP core virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set& in_rset, fd_set& in_wset) { return netclient->Poll(in_rset, in_wset); } virtual int ParseData(); virtual int Shutdown(); virtual int Reconnect(); protected: SerialClient *sercli; int gpseventid; char device[128]; int last_mode; time_t last_hed_time; }; #endif kismet-2013-03-R1b/kis_netframe.h0000664000175000017500000002155512124602454016303 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISNETFRAME_H__ #define __KISNETFRAME_H__ #include "config.h" #include "util.h" #include "messagebus.h" #include "netframework.h" #include "packetchain.h" // Forward prototype class KisNetFramework; // Caching record for sending stuff to multiple clients, gets filled in with // what needs to be sent via the protocol pointers class kis_protocol_cache { public: kis_protocol_cache() { numfields = 0; } ~kis_protocol_cache() { } int Filled(int in_f) { if (CacheResize(in_f)) return 0; return field_filled[in_f]; } void Cache(int in_f, string in_val) { CacheResize(in_f); field_cache[in_f] = in_val; field_filled[in_f] = 1; } string GetCache(int in_f) { if (CacheResize(in_f)) return ""; return field_cache[in_f]; } protected: int CacheResize(int in_f) { if (in_f < numfields) return 0; field_cache.resize(in_f + 1, string("")); field_filled.resize(in_f + 1, 0); /* for (int x = numfields; x < in_f; x++) { field_filled[x] = 0; } */ numfields = in_f + 1; return 1; } vector field_cache; vector field_filled; int numfields; }; // Client command structure for incoming commands. Given the ID of the client // and the parsed ID of the command, the server framework, the globals, and the // remainder of the command line (after cmdid and command itself). For extra // fun we pass the cmdline we split apart #define CLIENT_PARMS int in_clid, KisNetFramework *framework, \ GlobalRegistry *globalreg, char *errstr, string cmdline, \ vector *parsedcmdline, void *auxptr typedef int (*ClientCommand)(CLIENT_PARMS); // Protocol parameters #define PROTO_PARMS string& out_string, const vector *field_vec, \ const void *data, const void *auxptr, kis_protocol_cache *cache, \ GlobalRegistry *globalreg typedef int (*ProtoCallback)(PROTO_PARMS); #define PROTO_ENABLE_PARMS int in_fd, GlobalRegistry *globalreg, \ const void *data typedef void (*ProtoEnableCallback)(PROTO_ENABLE_PARMS); // Lowlevel protocols that get inserted into the server during setup, these // MUST be supported ASAP enum KISMET_fields { KISMET_version, KISMET_starttime, KISMET_servername, KISMET_dumpfiles, KISMET_uid, KISMET_max }; enum ERROR_fields { ERROR_cmdid, ERROR_cmdtext }; enum ACK_fields { ACK_cmdid, ACK_cmdtext }; enum PROTOCOL_fields { PROTOCOL_protocols }; enum CAPABILITY_fields { CAPABILITY_capabilities }; enum TERMINATE_fields { TERMINATE_text }; enum TIME_fields { TIME_timesec }; enum STATUS_fields { STATUS_text, STATUS_flags }; enum PACKET_fields { PACKET_type, PACKET_subtype, PACKET_timesec, PACKET_encrypted, PACKET_weak, PACKET_beaconrate, PACKET_sourcemac, PACKET_destmac, PACKET_bssid, PACKET_ssid, PACKET_prototype, PACKET_sourceip, PACKET_destip, PACKET_sourceport, PACKET_destport, PACKET_nbtype, PACKET_nbsource, PACKET_sourcename }; // Client/server protocol data structures. These get passed as void *'s to each // of the protocol functions. // These are all done in two main ways - a var for each field, or a vector in the // same order as the field names. struct PACKET_data { vector pdvec; }; struct STATUS_data { string text; int flags; }; int Protocol_KISMET(PROTO_PARMS); int Protocol_ERROR(PROTO_PARMS); int Protocol_ACK(PROTO_PARMS); int Protocol_PROTOCOLS(PROTO_PARMS); int Protocol_CAPABILITY(PROTO_PARMS); int Protocol_TERMINATE(PROTO_PARMS); int Protocol_TIME(PROTO_PARMS); int Protocol_STATUS(PROTO_PARMS); // STATUS_data void Protocol_Packet2Data(const kis_packet *info, PACKET_data *data); int Protocol_PACKET(PROTO_PARMS); // PACKET_data int Protocol_WEPKEY(PROTO_PARMS); // wep_key_info struct KISMET_data { string version; string starttime; string servername; string timestamp; string newversion; int uid; }; struct CLIRESP_data { int cmdid; string resptext; }; // Builtin commands we have to handle int Clicmd_CAPABILITY(CLIENT_PARMS); int Clicmd_ENABLE(CLIENT_PARMS); int Clicmd_REMOVE(CLIENT_PARMS); int Clicmd_LISTWEPKEYS(CLIENT_PARMS); int Clicmd_ADDWEPKEY(CLIENT_PARMS); int Clicmd_DELWEPKEY(CLIENT_PARMS); // Messagebus subscriber to pass data to the client class KisNetframe_MessageClient : public MessageClient { public: KisNetframe_MessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { }; virtual ~KisNetframe_MessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; // Timer events int KisNetFrame_TimeEvent(Timetracker::timer_event *evt, void *parm, GlobalRegistry *globalreg); // Kismet server framework for sending data to clients and processing // commands from clients class KisNetFramework : public ServerFramework { public: struct server_protocol { int ref_index; string header; int required; int cacheable; // Double-listed (burns a little extra ram but not much) to make // mapping requested fields fast. map field_map; vector field_vec; int (*printer)(PROTO_PARMS); void (*enable)(PROTO_ENABLE_PARMS); void *auxptr; }; struct client_command_rec { void *auxptr; ClientCommand cmd; }; KisNetFramework(); KisNetFramework(GlobalRegistry *in_globalreg); virtual ~KisNetFramework(); // Activate the setup int Activate(); virtual int Accept(int in_fd); virtual int ParseData(int in_fd); virtual int KillConnection(int in_fd); virtual int Shutdown(); // Handle a buffer drain on a client virtual int BufferDrained(int in_fd); // Send a protocol to a specific client int SendToClient(int in_fd, int in_refnum, const void *in_data, kis_protocol_cache *in_cache); // Send to all clients int SendToAll(int in_refnum, const void *in_data); // Learn a client command int RegisterClientCommand(string in_cmdword, ClientCommand in_cmd, void *in_auxdata); int RemoveClientCommand(string in_cmdword); // Register an output sentence. This needs: // * A header (ie, NETWORK) // * A NULL-terminated array of fields // * A pointer to a printer that takes a void * and a vector of field numbers // and outputs a c++ string // * An optional pointer to a function that takes the file descriptor of a client // that triggers whatever events should happen the the client enables this kind // of protocol. (ie, send all networks when the client enables the *NETWORK // protocol) // It returns the index number of the sentence added. int RegisterProtocol(string in_header, int in_required, int in_cache, const char **in_fields, int (*in_printer)(PROTO_PARMS), void (*in_enable)(PROTO_ENABLE_PARMS), void *in_auxdata); int RemoveProtocol(int in_protoref); int FetchProtocolRef(string in_header); KisNetFramework::server_protocol *FetchProtocol(int in_ref); // Manipulate client info void AddProtocolClient(int in_fd, int in_refnum, vector in_fields); void DelProtocolClient(int in_fd, int in_refnum); // How many clients are using this protocol type? int FetchNumClientRefs(int in_refnum); // How many clients total? int FetchNumClients(); // Usage static void Usage(char *name); protected: int next_netprotoref; // Messagebus client KisNetframe_MessageClient *kisnet_msgcli; // Client options struct client_opt { // Map of sentence references to field lists map > protocols; vector backlog; }; // Client commands we understand map client_cmd_map; // Map of reference numbers to sentences map protocol_map; // Map of headers to reference numbers map ref_map; // Protocols clients are required to support vector required_protocols; // Map of protocols to the number of clients using them map client_mapped_protocols; // Client options map client_optmap; // Server type (0 = tcp...) int server_type; // Max backlog int maxbacklog; }; #endif kismet-2013-03-R1b/serialclient.h0000664000175000017500000000410012124602454016275 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __SERIALCLIENT_H__ #define __SERIALCLIENT_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuf.h" #include "messagebus.h" #include "timetracker.h" #include "clinetframework.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif // Arbitrary 16k ring. #define SER_RING_LEN (16384) class SerialClient : public NetworkClient { public: SerialClient(); SerialClient(GlobalRegistry *in_globalreg); virtual ~SerialClient(); // Bastardized Connect() overload - port ignored, remotehost // used as path to serial devie virtual int Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux); // Set serial port attributes virtual int GetOptions(struct termios *options); virtual int SetOptions(int optmode, struct termios *options); virtual int SetBaud(int in_baud); virtual int FlushSerial(int in_selector); protected: virtual int Validate() { return 1; } virtual int ReadBytes(); virtual int WriteBytes(); }; #endif kismet-2013-03-R1b/messagebus.h0000664000175000017500000000531012124602454015761 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __MESSAGEBUS_H__ #define __MESSAGEBUS_H__ #include "config.h" #include #include #include "globalregistry.h" // Message flags for queuing data #define MSGFLAG_NONE 0 #define MSGFLAG_DEBUG 1 #define MSGFLAG_INFO 2 #define MSGFLAG_ERROR 4 #define MSGFLAG_ALERT 8 #define MSGFLAG_FATAL 16 // Don't propagate it past local display systems #define MSGFLAG_LOCAL 32 // Force printing of the error in the shutdown messages, sort of a "fatal lite" #define MSGFLAG_PRINT 64 #define MSGFLAG_ALL (MSGFLAG_DEBUG | MSGFLAG_INFO | \ MSGFLAG_ERROR | MSGFLAG_ALERT | \ MSGFLAG_FATAL) // Combine #define MSGFLAG_PRINTERROR (MSGFLAG_ERROR | MSGFLAG_PRINT) // A subscriber to the message bus. It subscribes with a mask of // what messages it wants to handle class MessageClient { public: MessageClient() { fprintf(stderr, "FATAL OOPS: MessageClient::MessageClient() called " "with no global registry\n"); exit(1); } MessageClient(GlobalRegistry *in_globalreg, void *in_aux) { globalreg = in_globalreg; auxptr = in_aux; } virtual ~MessageClient() { } virtual void ProcessMessage(string in_msg, int in_flags) = 0; protected: GlobalRegistry *globalreg; void *auxptr; }; class StdoutMessageClient : public MessageClient { public: StdoutMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~StdoutMessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; class MessageBus { public: // Inject a message into the bus void InjectMessage(string in_msg, int in_flags); // Link a meessage display system void RegisterClient(MessageClient *in_subcriber, int in_mask); void RemoveClient(MessageClient *in_unsubscriber); protected: typedef struct { MessageClient *client; int mask; } busclient; vector subscribers; }; #endif kismet-2013-03-R1b/kismet_server.cc0000664000175000017500000011117412124602454016651 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #define KISMET_SERVER #include "version.h" #include #include #include #include #include "getopt.h" #include #include #include #include #include #include #include "util.h" #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "plugintracker.h" #include "packetsource.h" #include "packetsource_bsdrt.h" #include "packetsource_pcap.h" #include "packetsource_wext.h" #include "packetsource_drone.h" #include "packetsource_ipwlive.h" #include "packetsource_airpcap.h" #include "packetsource_darwin.h" #include "packetsource_macusb.h" #include "packetsourcetracker.h" #include "timetracker.h" #include "alertracker.h" #include "netframework.h" #include "tcpserver.h" #include "kis_netframe.h" #include "kis_droneframe.h" #include "soundcontrol.h" #include "gpswrapper.h" #include "packetdissectors.h" #include "netracker.h" #include "devicetracker.h" #include "phy_80211.h" #include "channeltracker.h" #include "dumpfile.h" #include "dumpfile_pcap.h" #include "dumpfile_netxml.h" #include "dumpfile_nettxt.h" #include "dumpfile_gpsxml.h" #include "dumpfile_tuntap.h" #include "dumpfile_string.h" #include "dumpfile_alert.h" #include "ipc_remote.h" #include "statealert.h" #include "manuf.h" #include "battery.h" #ifndef exec_name char *exec_name; #endif // Daemonize? int daemonize = 0; // Plugins? int plugins = 1; // One of our few globals in this file int glob_linewrap = 1; int glob_silent = 0; int battery_proto_ref = -1; int critfail_proto_ref = -1; // The info protocol lives in here for lack of anywhere better to live enum INFO_fields { INFO_networks, INFO_packets, INFO_cryptpackets, INFO_noisepackets, INFO_droppedpackets, INFO_packetrate, INFO_filteredpackets, INFO_clients, INFO_llcpackets, INFO_datapackets, INFO_numsources, INFO_numerrorsources, INFO_maxfield }; const char *INFO_fields_text[] = { "networks", "packets", "crypt", "noise", "dropped", "rate", "filtered", "clients", "llcpackets", "datapackets", "numsources", "numerrorsources", NULL }; enum BATTERY_fields { BATTERY_percentage, BATTERY_charging, BATTERY_ac, BATTERY_remaining, BATTERY_maxfield }; const char *BATTERY_fields_text[] = { "percentage", "charging", "ac", "remaining", NULL }; enum CRITFAIL_fields { CRITFAIL_id, CRITFAIL_time, CRITFAIL_message, CRITFAIL_maxfield }; const char *CRITFAIL_fields_text[] = { "id", "time", "message", NULL }; int Protocol_INFO(PROTO_PARMS) { ostringstream osstr; int num_error; vector *sourcevec = globalreg->sourcetracker->FetchSourceVec(); // Alloc the cache quickly cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= INFO_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); // Shortcut test the cache once and print/bail immediately if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } // Fill in the cached element switch(fnum) { case INFO_networks: osstr << globalreg->netracker->FetchNumNetworks(); cache->Cache(fnum, osstr.str()); break; case INFO_clients: osstr << globalreg->netracker->FetchNumClients(); cache->Cache(fnum, osstr.str()); break; case INFO_packets: osstr << globalreg->netracker->FetchNumPackets(); cache->Cache(fnum, osstr.str()); break; case INFO_cryptpackets: osstr << globalreg->netracker->FetchNumCryptpackets(); cache->Cache(fnum, osstr.str()); break; case INFO_llcpackets: osstr << globalreg->netracker->FetchNumLLCpackets(); cache->Cache(fnum, osstr.str()); break; case INFO_datapackets: osstr << globalreg->netracker->FetchNumDatapackets(); cache->Cache(fnum, osstr.str()); break; case INFO_noisepackets: osstr << globalreg->netracker->FetchNumErrorpackets(); cache->Cache(fnum, osstr.str()); break; case INFO_droppedpackets: osstr << (globalreg->netracker->FetchNumErrorpackets() + globalreg->netracker->FetchNumFiltered()); cache->Cache(fnum, osstr.str()); break; case INFO_packetrate: osstr << globalreg->netracker->FetchPacketRate(); cache->Cache(fnum, osstr.str()); break; case INFO_filteredpackets: osstr << globalreg->netracker->FetchNumFiltered(); cache->Cache(fnum, osstr.str()); break; case INFO_numsources: osstr << sourcevec->size(); cache->Cache(fnum, osstr.str()); break; case INFO_numerrorsources: num_error = 0; for (unsigned int e = 0; e < sourcevec->size(); e++) { if ((*sourcevec)[e]->error) num_error++; } osstr << num_error; cache->Cache(fnum, osstr.str()); break; } // print the newly filled in cache out_string += cache->GetCache(fnum) + " "; } return 1; } int Protocol_BATTERY(PROTO_PARMS) { kis_battery_info *b = (kis_battery_info *) data; string scratch; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= BATTERY_maxfield) { out_string += "Unknown field requested."; return -1; } if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case BATTERY_percentage: scratch = IntToString(b->percentage); break; case BATTERY_charging: scratch = IntToString(b->charging); break; case BATTERY_ac: scratch = IntToString(b->ac); break; case BATTERY_remaining: scratch = IntToString(b->remaining_sec); break; } out_string += scratch; cache->Cache(fnum, scratch); out_string += " "; } return 1; } void Protocol_CRITFAIL_enable(PROTO_ENABLE_PARMS) { for (unsigned int x = 0; x < globalreg->critfail_vec.size(); x++) { kis_protocol_cache cache; if (in_fd == -1) { if (globalreg->kisnetserver->SendToAll(critfail_proto_ref, (void *) x) < 0) break; } else { if (globalreg->kisnetserver->SendToClient(in_fd, critfail_proto_ref, (void *) x, &cache) < 0) break; } // Often enough to be really obvious if (time(0) % 5 == 0) _MSG("!!! CRITICAL ERROR !!! - " + globalreg->critfail_vec[x].fail_msg + " - Kismet will not operate correctly.", MSGFLAG_FATAL); } } int Protocol_CRITFAIL(PROTO_PARMS) { // This is stupid but it makes gcc shut up. Maybe. unsigned long int cf_lnum = (unsigned long int) data; unsigned int cf_num = (unsigned int) cf_lnum; if (cf_num >= globalreg->critfail_vec.size()) cf_num = 0; string scratch; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= CRITFAIL_maxfield) { out_string += "Unknown field requested."; return -1; } if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case CRITFAIL_id: scratch = IntToString(cf_num); break; case CRITFAIL_time: scratch = IntToString(globalreg->critfail_vec[cf_num].fail_time); break; case CRITFAIL_message: scratch = "\001" + globalreg->critfail_vec[cf_num].fail_msg + "\001"; break; } out_string += scratch; cache->Cache(fnum, scratch); out_string += " "; } return 1; } // Message clients that are attached at the master level // Smart standard out client that understands the silence options class SmartStdoutMessageClient : public MessageClient { public: SmartStdoutMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~SmartStdoutMessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; void SmartStdoutMessageClient::ProcessMessage(string in_msg, int in_flags) { if (glob_silent) return; if ((in_flags & MSGFLAG_DEBUG)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("DEBUG: " + in_msg, 7, 75).c_str()); else fprintf(stdout, "DEBUG: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_LOCAL)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("LOCAL: " + in_msg, 7, 75).c_str()); else fprintf(stdout, "LOCAL: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_INFO)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("INFO: " + in_msg, 6, 75).c_str()); else fprintf(stdout, "INFO: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ERROR)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ERROR: " + in_msg, 7, 75).c_str()); else fprintf(stdout, "ERROR: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ALERT)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ALERT: " + in_msg, 7, 75).c_str()); else fprintf(stdout, "ALERT: %s\n", in_msg.c_str()); } else if (in_flags & MSGFLAG_FATAL) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap("FATAL: " + in_msg, 7, 75).c_str()); else fprintf(stderr, "FATAL: %s\n", in_msg.c_str()); } fflush(stdout); fflush(stderr); return; } // Queue of fatal alert conditions to spew back out at the end class FatalQueueMessageClient : public MessageClient { public: FatalQueueMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~FatalQueueMessageClient() { } void ProcessMessage(string in_msg, int in_flags); void DumpFatals(); protected: vector fatalqueue; }; void FatalQueueMessageClient::ProcessMessage(string in_msg, int in_flags) { // Queue PRINT forced errors differently than fatal conditions if (in_flags & MSGFLAG_PRINT) { fatalqueue.push_back("ERROR: " + in_msg); } else if (in_flags & MSGFLAG_FATAL) { fatalqueue.push_back("FATAL: " + in_msg); } } void FatalQueueMessageClient::DumpFatals() { for (unsigned int x = 0; x < fatalqueue.size(); x++) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap(fatalqueue[x], 7, 80).c_str()); else fprintf(stderr, "%s\n", fatalqueue[x].c_str()); } } const char *config_base = "kismet.conf"; const char *pid_base = "kismet_server.pid"; // This needs to be a global but nothing outside of this main file will // use it, so we don't have to worry much about putting it in the globalreg. FatalQueueMessageClient *fqmescli = NULL; // Some globals for command line options char *configfile = NULL; int packnum = 0, localdropnum = 0; // Ultimate registry of global components GlobalRegistry *globalregistry = NULL; // Catch our interrupt void CatchShutdown(int sig) { if (sig == 0) { kill(getpid(), SIGTERM); return; } string termstr = "Kismet server terminating."; // Eat the child signal handler signal(SIGCHLD, SIG_DFL); if (globalregistry->kisnetserver != NULL) { globalregistry->kisnetserver->SendToAll(globalregistry->netproto_map[PROTO_REF_TERMINATE], (void *) &termstr); } if (globalregistry->sourcetracker != NULL) { // Shut down the packet sources globalregistry->sourcetracker->StopSource(0); } globalregistry->spindown = 1; // Start a short shutdown cycle for 2 seconds if (daemonize == 0) fprintf(stderr, "\n*** KISMET IS SHUTTING DOWN ***\n"); time_t shutdown_target = time(0) + 2; int max_fd = 0; fd_set rset, wset; struct timeval tm; while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) { break; } if (time(0) >= shutdown_target) { break; } // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { break; } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { break; } } } if (globalregistry->rootipc != NULL) { // Shut down the channel control child globalregistry->rootipc->ShutdownIPC(NULL);; } if (globalregistry->kisnetserver != NULL) { globalregistry->kisnetserver->Shutdown(); } // Be noisy if (globalregistry->fatal_condition) { fprintf(stderr, "\n*** KISMET HAS ENCOUNTERED A FATAL ERROR AND CANNOT " "CONTINUE. ***\n"); } // Kill all the logfiles fprintf(stderr, "Shutting down log files...\n"); for (unsigned int x = 0; x < globalregistry->subsys_dumpfile_vec.size(); x++) { delete globalregistry->subsys_dumpfile_vec[x]; } globalregistry->pcapdump = NULL; if (globalregistry->plugintracker != NULL) globalregistry->plugintracker->ShutdownPlugins(); if (globalregistry->netracker != NULL) { delete globalregistry->netracker; globalregistry->netracker = NULL; } if (globalregistry->devicetracker != NULL) { delete globalregistry->devicetracker; globalregistry->devicetracker = NULL; } // Dump fatal errors again if (fqmescli != NULL) // && globalregistry->fatal_condition) fqmescli->DumpFatals(); if (daemonize == 0) { fprintf(stderr, "WARNING: Kismet changes the configuration of network devices.\n" " In most cases you will need to restart networking for\n" " your interface (varies per distribution/OS, but \n" " usually: /etc/init.d/networking restart\n\n"); fprintf(stderr, "Kismet exiting.\n"); } exit(0); } void CatchChild(int sig) { int status; pid_t pid; if (globalregistry->spindown) return; // printf("debug - sigchild\n"); while (1) { pid = waitpid(-1, &status, WNOHANG); // printf("debug - pid %d status %d exit %d\n", pid, status, WEXITSTATUS(status)); if (pid != 0) break; } if (pid < 0) { return; } pid_fail frec; frec.pid = pid; frec.status = status; globalregistry->sigchild_vec.push_back(frec); } int Usage(char *argv) { printf("Usage: %s [OPTION]\n", argv); printf("Nearly all of these options are run-time overrides for values in the\n" "kismet.conf configuration file. Permanent changes should be made to\n" "the configuration file.\n"); printf(" *** Generic Options ***\n"); printf(" -v, --version Show version\n" " -f, --config-file Use alternate configuration file\n" " --no-line-wrap Turn of linewrapping of output\n" " (for grep, speed, etc)\n" " -s, --silent Turn off stdout output after setup phase\n" " --daemonize Spawn detatched in the background\n" " --no-plugins Do not load plugins\n" " --no-root Do not start the kismet_capture binary \n" " when not running as root. For no-priv \n" " remote capture ONLY.\n" ); printf("\n"); KisNetFramework::Usage(argv); printf("\n"); KisDroneFramework::Usage(argv); printf("\n"); Dumpfile::Usage(argv); printf("\n"); Packetsourcetracker::Usage(argv); printf("\n"); Netracker::Usage(argv); printf("\n"); GpsWrapper::Usage(argv); exit(1); } int FlushDatafilesEvent(TIMEEVENT_PARMS) { if (globalreg->subsys_dumpfile_vec.size() == 0) return 1; int r = 0; for (unsigned int x = 0; x < globalreg->subsys_dumpfile_vec.size(); x++) { if (globalreg->subsys_dumpfile_vec[x]->Flush()) r = 1; } if (r) _MSG("Saved data files", MSGFLAG_INFO); return 1; } int BaseTimerEvent(TIMEEVENT_PARMS) { // Send the info frame to everyone globalreg->kisnetserver->SendToAll(_NPM(PROTO_REF_INFO), NULL); // Send the battery frame kis_battery_info batinfo; Fetch_Battery_Info(&batinfo); globalreg->kisnetserver->SendToAll(battery_proto_ref, &batinfo); // Send critfails to everyone and print out as messages Protocol_CRITFAIL_enable(-1, globalreg, NULL); return 1; } int cmd_SHUTDOWN(CLIENT_PARMS) { _MSG("Received SHUTDOWN command", MSGFLAG_FATAL); CatchShutdown(0); return 1; } int main(int argc, char *argv[], char *envp[]) { exec_name = argv[0]; char errstr[STATUS_MAX]; char *configfilename = NULL; ConfigFile *conf; int option_idx = 0; int data_dump = 0; GlobalRegistry *globalreg; // Timer for silence int local_silent = 0; int startroot = 1; // Catch the interrupt handler to shut down signal(SIGINT, CatchShutdown); signal(SIGTERM, CatchShutdown); signal(SIGHUP, CatchShutdown); signal(SIGQUIT, CatchShutdown); signal(SIGCHLD, CatchChild); signal(SIGPIPE, SIG_IGN); // Start filling in key components of the globalregistry globalregistry = new GlobalRegistry; globalreg = globalregistry; globalregistry->version_major = VERSION_MAJOR; globalregistry->version_minor = VERSION_MINOR; globalregistry->version_tiny = VERSION_TINY; globalregistry->revision = REVISION; globalregistry->revdate = REVDATE; // Copy for modules globalregistry->argc = argc; globalregistry->argv = argv; globalregistry->envp = envp; int startup_ipc_id = -1; int max_fd = 0; fd_set rset, wset; struct timeval tm; // Turn off the getopt error reporting opterr = 0; optind = 0; const int nlwc = globalregistry->getopt_long_num++; const int dwc = globalregistry->getopt_long_num++; const int npwc = globalregistry->getopt_long_num++; const int nrwc = globalregistry->getopt_long_num++; // Standard getopt parse run static struct option main_longopt[] = { { "version", no_argument, 0, 'v' }, { "config-file", required_argument, 0, 'f' }, { "no-line-wrap", no_argument, 0, nlwc }, { "silent", no_argument, 0, 's' }, { "help", no_argument, 0, 'h' }, { "daemonize", no_argument, 0, dwc }, { "no-plugins", no_argument, 0, npwc }, { "no-root", no_argument, 0, nrwc }, { 0, 0, 0, 0 } }; // Reset the options index optind = 0; option_idx = 0; while (1) { int r = getopt_long(argc, argv, "-f:sp:hv", main_longopt, &option_idx); if (r < 0) break; if (r == 'v') { printf("Kismet %s-%s-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_TINY); exit(1); } else if (r == 'h') { Usage(argv[0]); exit(1); } else if (r == 'f') { configfilename = strdup(optarg); } else if (r == nlwc) { glob_linewrap = 0; } else if (r == 's') { local_silent = 1; } else if (r == dwc) { daemonize = 1; local_silent = 1; } else if (r == npwc) { plugins = 0; } else if (r == nrwc) { startroot = 0; } } // First order - create our message bus and our client for outputting globalregistry->messagebus = new MessageBus; // Create a smart stdout client and allocate the fatal message client, // add them to the messagebus SmartStdoutMessageClient *smartmsgcli = new SmartStdoutMessageClient(globalregistry, NULL); fqmescli = new FatalQueueMessageClient(globalregistry, NULL); // Register the fatal queue with fatal and error messages globalregistry->messagebus->RegisterClient(fqmescli, MSGFLAG_FATAL | MSGFLAG_ERROR); // Register the smart msg printer for everything globalregistry->messagebus->RegisterClient(smartmsgcli, MSGFLAG_ALL); #ifndef SYS_CYGWIN // Generate the root ipc packet capture and spawn it immediately, then register // and sync the packet protocol stuff if (getuid() != 0 && startroot == 0) { globalregistry->messagebus->InjectMessage("Not running as root, and --no-root " "was requested. Will not attempt to spawn Kismet capture binary. This " "will make it impossible to add sources which require root.", MSGFLAG_INFO | MSGFLAG_PRINTERROR); } else if (getuid() != 0) { globalregistry->messagebus->InjectMessage("Not running as root - will try to " "launch root control binary (" + string(BIN_LOC) + "/kismet_capture) to " "control cards.", MSGFLAG_INFO); globalregistry->rootipc = new RootIPCRemote(globalregistry, "kismet_root"); globalregistry->rootipc->SpawnIPC(); startup_ipc_id = globalregistry->rootipc->RegisterIPCCmd(NULL, NULL, NULL, "STARTUP"); time_t ipc_spin_start = time(0); while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } if (globalregistry->rootipc->FetchRootIPCSynced() > 0) { // printf("debug - kismet server startup got root sync\n"); break; } if (time(0) - ipc_spin_start > 2) { // printf("debug - kismet server startup timed out\n"); break; } } if (globalregistry->rootipc->FetchRootIPCSynced() <= 0) { critical_fail cf; cf.fail_time = time(0); cf.fail_msg = "Failed to start kismet_capture control binary. Make sure " "that kismet_capture is installed, is suid-root, and that your user " "is in the 'kismet' group, or run Kismet as root. See the " "README for more information."; int ipc_errno = globalregistry->rootipc->FetchErrno(); if (ipc_errno == EPERM || ipc_errno == EACCES) { cf.fail_msg = "Could not launch kismet_capture control binary, " "due to permission errors. To run Kismet suid-root your user " "MUST BE IN THE 'kismet' GROUP. Use the 'groups' command to show " "what groups your user is in, and consult the Kismet README for " "more information."; } globalreg->critfail_vec.push_back(cf); _MSG(cf.fail_msg, MSGFLAG_FATAL); } else { _MSG("Started kismet_capture control binary successfully, pid " + IntToString(globalreg->rootipc->FetchSpawnPid()), MSGFLAG_INFO); } } else { globalregistry->messagebus->InjectMessage( "Kismet was started as root, NOT launching external control binary. " "This is NOT the preferred method of starting Kismet as Kismet will " "continue to run as root the entire time. Please read the README " "file section about Installation & Security and be sure this is " "what you want to do.", MSGFLAG_ERROR); } #endif // Allocate some other critical stuff globalregistry->timetracker = new Timetracker(globalregistry); // Open, initial parse, and assign the config file if (configfilename == NULL) { configfilename = new char[1024]; snprintf(configfilename, 1024, "%s/%s", getenv("KISMET_CONF") != NULL ? getenv("KISMET_CONF") : SYSCONF_LOC, config_base); } snprintf(errstr, STATUS_MAX, "Reading from config file %s", configfilename); globalregistry->messagebus->InjectMessage(errstr, MSGFLAG_INFO); conf = new ConfigFile(globalregistry); if (conf->ParseConfig(configfilename) < 0) { exit(1); } globalregistry->kismet_config = conf; if (daemonize) { if (fork() != 0) { fprintf(stderr, "Silencing output and entering daemon mode...\n"); exit(1); } // remove messagebus clients globalregistry->messagebus->RemoveClient(fqmescli); globalregistry->messagebus->RemoveClient(smartmsgcli); } if (conf->FetchOpt("servername") == "") { char hostname[64]; if (gethostname(hostname, 64) < 0) globalregistry->servername = "Kismet"; else globalregistry->servername = string(hostname); } else { globalregistry->servername = MungeToPrintable(conf->FetchOpt("servername")); } // Create the basic network/protocol server globalregistry->kisnetserver = new KisNetFramework(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); globalregistry->kisnetserver->RegisterClientCommand("SHUTDOWN", &cmd_SHUTDOWN, NULL); // Start the plugin handler if (plugins) { globalregistry->plugintracker = new Plugintracker(globalregistry); } else { globalregistry->messagebus->InjectMessage( "Plugins disabled on the command line, plugins will NOT be loaded...", MSGFLAG_INFO); } // Create the packet chain globalregistry->packetchain = new Packetchain(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the packetsourcetracker globalregistry->sourcetracker = new Packetsourcetracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Register the IPC if (globalregistry->rootipc != NULL) { globalregistry->sourcetracker->RegisterIPC(globalregistry->rootipc, 0); } #ifndef SYS_CYGWIN // Prep the tuntap device Dumpfile_Tuntap *dtun = new Dumpfile_Tuntap(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); #endif // Sync the IPC system -- everything that needs to be registered with the root // IPC needs to be registered before now if (globalregistry->rootipc != NULL) { globalregistry->rootipc->SyncRoot(); globalregistry->rootipc->SyncIPC(); #if 0 // Another startup spin to make sure the sync flushes through time_t ipc_spin_start = time(0); while (1) { printf("debug - sync spin\n"); FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } if (globalregistry->rootipc->FetchReadyState() > 0) { printf("debug - ready\n"); break; } if (time(0) - ipc_spin_start > 2) { printf("debug - timed out on sync spin\n"); break; } } printf("debug - out of sync spin\n"); #endif } #ifndef SYS_CYGWIN // Fire the tuntap device setup now that we've sync'd the IPC system dtun->OpenTuntap(); #endif // Fire the startup command to IPC, we're done and it can drop privs if (globalregistry->rootipc != NULL) { ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet)); ipc->data_len = 0; ipc->ipc_ack = 0; ipc->ipc_cmdnum = startup_ipc_id; globalreg->rootipc->SendIPC(ipc); } // Create the basic drone server globalregistry->kisdroneserver = new KisDroneFramework(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the alert tracker globalregistry->alertracker = new Alertracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the device tracker _MSG("Creating device tracker...", MSGFLAG_INFO); globalregistry->devicetracker = new Devicetracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Register the base PHYs if (globalregistry->devicetracker->RegisterPhyHandler(new Kis_80211_Phy(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); // Add the packet sources #ifdef USE_PACKETSOURCE_PCAPFILE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Pcapfile(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WEXT if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Wext(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFI if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Madwifi(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFING if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_MadwifiNG(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WRT54PRISM if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Wrt54Prism(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DRONE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Drone(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_BSDRT if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_BSDRT(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_IPWLIVE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Ipwlive(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_AIRPCAP if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_AirPcap(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DARWIN if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Darwin(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MACUSB if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_MacUSB(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif // Process userspace plugins if (globalregistry->plugintracker != NULL) { globalregistry->plugintracker->ScanUserPlugins(); globalregistry->plugintracker->ActivatePlugins(); if (globalregistry->fatal_condition) { globalregistry->messagebus->InjectMessage( "Failure during activating plugins", MSGFLAG_FATAL); CatchShutdown(-1); } } // Enable cards from config/cmdline if (globalregistry->sourcetracker->LoadConfiguration() < 0) CatchShutdown(-1); // Create the basic network/protocol server globalregistry->kisnetserver->Activate(); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the basic drone server globalregistry->kisdroneserver->Activate(); if (globalregistry->fatal_condition) CatchShutdown(-1); // Register basic chain elements... This is just instantiating a util class. // Nothing else talks to it, so we don't have to care about following it globalregistry->messagebus->InjectMessage("Inserting basic packet dissectors...", MSGFLAG_INFO); globalregistry->builtindissector = new KisBuiltinDissector(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Assign the speech and sound handlers globalregistry->soundctl = new SoundControl(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the GPS components GpsWrapper *gpswrapper; globalregistry->messagebus->InjectMessage("Starting GPS components...", MSGFLAG_INFO); gpswrapper = new GpsWrapper(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the manuf db globalregistry->manufdb = new Manuf(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the network tracker globalregistry->messagebus->InjectMessage("Creating network tracker...", MSGFLAG_INFO); globalregistry->netracker = new Netracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the channel tracker globalregistry->messagebus->InjectMessage("Creating channel tracker...", MSGFLAG_INFO); Channeltracker *chantracker; chantracker = new Channeltracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the dumpfiles. We don't have to assign the new dumpfile anywhere // because it puts itself in the global vector globalregistry->messagebus->InjectMessage("Registering dumpfiles...", MSGFLAG_INFO); #ifdef HAVE_LIBPCAP // Pcapdump is special since plugins might hook it globalreg->pcapdump = new Dumpfile_Pcap(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); #endif new Dumpfile_Netxml(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); new Dumpfile_Nettxt(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); new Dumpfile_Gpsxml(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); new Dumpfile_String(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); new Dumpfile_Alert(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); if (conf->FetchOpt("writeinterval") != "") { if (sscanf(conf->FetchOpt("writeinterval").c_str(), "%d", &data_dump) != 1) { data_dump = 0; globalregistry->messagebus->InjectMessage("Failed to parse data write " "interval from config file", MSGFLAG_ERROR); } } // Set the timer event to flush dumpfiles if (data_dump != 0 && globalregistry->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * data_dump, NULL, 1, &FlushDatafilesEvent, NULL) < 0) { globalregistry->messagebus->InjectMessage("Failed to register timer event to " "sync data files for some reason.", MSGFLAG_FATAL); CatchShutdown(-1); } // Start stateful alert systems BSSTSStateAlert *bsstsa; bsstsa = new BSSTSStateAlert(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Kick the plugin system one last time. This will try to kick any plugins // that aren't activated yet, and then bomb out if we can't turn them on at // all. if (globalregistry->plugintracker != NULL) { globalregistry->plugintracker->LastChancePlugins(); if (globalregistry->fatal_condition) CatchShutdown(-1); } // Initialize the crc tables crc32_init_table_80211(globalregistry->crc32_table); /* Register the info protocol */ _NPM(PROTO_REF_INFO) = globalregistry->kisnetserver->RegisterProtocol("INFO", 0, 1, INFO_fields_text, &Protocol_INFO, NULL, NULL); battery_proto_ref = globalregistry->kisnetserver->RegisterProtocol("BATTERY", 0, 1, BATTERY_fields_text, &Protocol_BATTERY, NULL, NULL); critfail_proto_ref = globalregistry->kisnetserver->RegisterProtocol("CRITFAIL", 0, 1, CRITFAIL_fields_text, &Protocol_CRITFAIL, &Protocol_CRITFAIL_enable, NULL); globalregistry->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &BaseTimerEvent, NULL); // Blab about starting globalregistry->messagebus->InjectMessage("Kismet starting to gather packets", MSGFLAG_INFO); // Start sources globalregistry->sourcetracker->StartSource(0); if (globalregistry->sourcetracker->FetchSourceVec()->size() == 0) { _MSG("No packet sources defined. You MUST ADD SOME using the Kismet " "client, or by placing them in the Kismet config file (" + string(SYSCONF_LOC) + "/" + config_base + ")", MSGFLAG_INFO); } // Set the global silence now that we're set up glob_silent = local_silent; // Core loop while (1) { // printf("debug - %d - main loop tick\n", getpid()); FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } globalregistry->timetracker->Tick(); for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } } CatchShutdown(-1); } kismet-2013-03-R1b/config.guess0000775000175000017500000012743212124602454016004 0ustar dragorndragorn#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file 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 2 of the License, or # (at your option) any later version. # # This program 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: kismet-2013-03-R1b/disable-plugin-dot15d4/0000775000175000017500000000000012124602454017534 5ustar dragorndragornkismet-2013-03-R1b/disable-plugin-dot15d4/packetsource_raven.cc0000664000175000017500000002276012124602454023735 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifdef SYS_LINUX #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packetsource_raven.h" #include "packet_dot15d4.h" PacketSource_Raven::PacketSource_Raven(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { thread_active = 0; devhdl = NULL; fake_fd[0] = -1; fake_fd[1] = -1; pending_packet = 0; d154_packet_id = globalreg->packetchain->RegisterPacketComponent("IEEE802_15_4"); ParseOptions(in_opts); } PacketSource_Raven::~PacketSource_Raven() { CloseSource(); } int PacketSource_Raven::ParseOptions(vector *in_opts) { KisPacketSource::ParseOptions(in_opts); if (FetchOpt("device", in_opts) != "") { usb_dev = FetchOpt("usbdev", in_opts); _MSG("RAVEN 802.15.4 using USB device '" + usb_dev + "'", MSGFLAG_INFO); } else { _MSG("RAVEN 802.15.4 using first USB device that looks like an ATAVRRZUSB", MSGFLAG_INFO); } return 1; } int PacketSource_Raven::AutotypeProbe(string in_device) { // Shortcut like we do on airport if (in_device == "raven") { type = "raven"; return 1; } return 0; } // Capture thread to fake async io void *raven_cap_thread(void *arg) { PacketSource_Raven *raven = (PacketSource_Raven *) arg; int len = 0; char *pkt; // printf("debug - cap thread\n"); while (raven->thread_active > 0) { pkt = new char[2048]; // Do a timered read since we need to catch when the thread is scheduled // to die. This uses more CPU. That's unfortunate. pthread_mutex_lock(&(raven->device_lock)); if ((len = usb_bulk_read(raven->devhdl, 0x81, pkt, 2048, 1000)) < 0) { if (errno != EAGAIN) { raven->thread_error = string(usb_strerror()); pthread_mutex_unlock(&(raven->device_lock)); break; } else { len = 0; } } pthread_mutex_unlock(&(raven->device_lock)); if (len == 0) { delete[] pkt; continue; } // printf("debug - thread got packet len %d\n", len); // Lock the packet queue, throw away when there are more than 20 in the queue // that haven't been handled, raise the file descriptor hot if we need to pthread_mutex_lock(&(raven->packet_lock)); if (raven->packet_queue.size() > 20) { // printf("debug - thread packet queue to big\n"); delete[] pkt; pthread_mutex_unlock(&(raven->packet_lock)); continue; } struct PacketSource_Raven::raven_pkt *rpkt = new PacketSource_Raven::raven_pkt; rpkt->data = pkt; rpkt->len = len; rpkt->channel = raven->last_channel; raven->packet_queue.push_back(rpkt); if (raven->pending_packet == 0) { // printf("debug - writing to fakefd\n"); raven->pending_packet = 1; write(raven->fake_fd[1], pkt, 1); } pthread_mutex_unlock(&(raven->packet_lock)); } raven->thread_active = -1; close(raven->fake_fd[1]); raven->fake_fd[1] = -1; pthread_exit((void *) 0); } int PacketSource_Raven::OpenSource() { struct usb_bus *bus = NULL; struct usb_device *dev = NULL; // Linux uses numbers, others might use strings int dev_cmp_id, dev_bus_id, found = 0; usb_init(); usb_find_busses(); usb_find_devices(); if (sscanf(usb_dev.c_str(), "%d", &dev_cmp_id) != 1) dev_cmp_id = -1; for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor != 0x03EB || dev->descriptor.idProduct != 0x210A) continue; // Match first if we don't care if (usb_dev == "") { found = 1; break; } // Match string if we can if (string(dev->filename) == usb_dev) { found = 1; break; } // Match int if it looks like a number (ie, linux id) if (sscanf(dev->filename, "%d", &dev_bus_id) == 1) { if (dev_cmp_id == dev_bus_id) { found = 1; break; } } } if (found) break; } if (found == 0) { if (usb_dev == "") { _MSG("RAVEN 802.15.4 unable to find any device which looked like an " "ATAVRRZUSB", MSGFLAG_ERROR); return 0; } else { _MSG("RAVEN 802.15.4 '" + name + "' unable to find device '" + usb_dev + "'. The USB device id changes each time the device is " "added or removed. Most times it will work better to let Kismet " "find the device automatically.", MSGFLAG_ERROR); return 0; } } if (usb_dev == "") usb_dev = string(dev->filename); if ((devhdl = usb_open(dev)) == NULL) { _MSG("RAVEN 802.15.4 '" + name + "' failed to open device '" + usb_dev + "': " + string(strerror(errno)), MSGFLAG_ERROR); return 0; } /* if (usb_detatch_kernel_driver_np(devhdl, 0) < 0) { } */ usb_set_configuration(devhdl, 1); if (usb_claim_interface(devhdl, 0) < 0) { _MSG("RAVEN 802.15.4 '" + name + "' failed to claim interface '" + usb_dev + "': " + string(usb_strerror()), MSGFLAG_ERROR); return 0; } /* Initialize the device, may fail if the device is already initialized, we * don't really care if that happens */ char init_cmd[1]; init_cmd[0] = 0x09; usb_bulk_write(devhdl, 0x02, init_cmd, 1, 10); usb_bulk_read(devhdl, 0x84, init_cmd, 1, 10); /* Initialize the pipe, mutex, and reading thread */ if (pipe(fake_fd) < 0) { _MSG("RAVEN 802.15.4 '" + name + "' failed to make a pipe() (this is really " "weird): " + string(strerror(errno)), MSGFLAG_ERROR); usb_close(devhdl); devhdl = NULL; return 0; } if (pthread_mutex_init(&packet_lock, NULL) < 0 || pthread_mutex_init(&device_lock, NULL) < 0) { _MSG("RAVEN 802.15.4 '" + name + "' failed to initialize pthread mutex: " + string(strerror(errno)), MSGFLAG_ERROR); usb_close(devhdl); devhdl = NULL; return 0; } /* Launch a capture thread */ thread_active = 1; pthread_create(&cap_thread, NULL, raven_cap_thread, this); return 1; } int PacketSource_Raven::CloseSource() { void *ret; if (thread_active > 0) { // Tell the thread to die thread_active = 0; // Grab it back pthread_join(cap_thread, &ret); // Kill the mutexes pthread_mutex_destroy(&device_lock); pthread_mutex_destroy(&packet_lock); } // Close the USB dev if (devhdl) { usb_close(devhdl); devhdl = NULL; } if (fake_fd[0] >= 0) { close(fake_fd[0]); fake_fd[0] = -1; } if (fake_fd[1] >= 0) { close(fake_fd[1]); fake_fd[1] = -1; } return 1; } int PacketSource_Raven::SetChannel(unsigned int in_ch) { char data[2]; int ret; if (in_ch < 11 || in_ch > 26) return -1; if (thread_active <= 0 || devhdl == NULL) return 0; data[0] = 0x07; data[1] = 0x00; if ((ret = usb_bulk_write(devhdl, 0x02, data, 2, 10)) < 0) { _MSG("RAVEN 802.15.4 '" + name + "' failed to write channel control: " + string(usb_strerror()), MSGFLAG_ERROR); return -1; } data[0] = 0x08; data[1] = (in_ch & 0xFF); if ((ret = usb_bulk_write(devhdl, 0x02, data, 2, 10)) < 0) { _MSG("RAVEN 802.15.4 '" + name + "' failed to write channel control: " + string(usb_strerror()), MSGFLAG_ERROR); return -1; } usb_bulk_read(devhdl, 0x84, data, 1, 10); last_channel = in_ch; return 1; } int PacketSource_Raven::FetchDescriptor() { // This is as good a place as any to catch a failure if (thread_active < 0) { _MSG("RAVEN 802.15.4 '" + name + "' capture thread failed: " + thread_error, MSGFLAG_INFO); CloseSource(); return -1; } return fake_fd[0]; } int PacketSource_Raven::Poll() { char rx; // Consume the junk byte we used to raise the FD high read(fake_fd[0], &rx, 1); pthread_mutex_lock(&packet_lock); pending_packet = 0; for (unsigned int x = 0; x < packet_queue.size(); x++) { kis_packet *newpack = globalreg->packetchain->GeneratePacket(); newpack->ts.tv_sec = globalreg->timestamp.tv_sec; newpack->ts.tv_usec = globalreg->timestamp.tv_usec; if (packet_queue[x]->len <= 9) { delete[] packet_queue[x]->data; continue; } kis_datachunk *rawchunk = new kis_datachunk; // Offset by the 9 bytes of junk at the beginning rawchunk->length = packet_queue[x]->len - 9; // Copy the packet w/out the crap from the raven (interpret RSSI later) rawchunk->data = new uint8_t[rawchunk->length]; memcpy(rawchunk->data, packet_queue[x]->data + 9, rawchunk->length); rawchunk->source_id = source_id; rawchunk->dlt = KDLT_IEEE802_15_4; newpack->insert(_PCM(PACK_COMP_LINKFRAME), rawchunk); // printf("debug - Got packet chan %d len=%d\n", packet_queue[x]->channel, packet_queue[x]->len); num_packets++; globalreg->packetchain->ProcessPacket(newpack); // Delete the temp struct and data delete packet_queue[x]->data; delete packet_queue[x]; } // Flush the queue packet_queue.clear(); // printf("debug - packet queue cleared %d\n", packet_queue.size()); pthread_mutex_unlock(&packet_lock); return 1; } #endif kismet-2013-03-R1b/disable-plugin-dot15d4/Makefile0000664000175000017500000000212512124602454021174 0ustar dragorndragorn# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ -lusb -lpthread CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC SRVOBJS = packetsource_raven.o packetsource_serialdev.o \ packet_dot15d4.o packet_dot15d4_types.o \ tracker_dot15d4.o kismet_dot15d4.o SRVOUT = dot15dot4.so all: $(SRVOUT) $(CLIOUT) $(CLIOUT): $(CLIOBJS) $(LD) $(PLUGINLDFLAGS) $(CLIOBJS) -o $(CLIOUT) $(LIBS) $(SRVOUT): $(SRVOBJS) $(LD) $(PLUGINLDFLAGS) $(SRVOBJS) -o $(SRVOUT) $(LIBS) install: $(SRVOUT) $(CLIOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $^ $(DESTDIR)/$(plugindir)/$(SRVOUT) userinstall: $(SRVOUT) $(CLIOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) -v $(SRVOUT) ${HOME}/.kismet/plugins/$(SRVOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o kismet-2013-03-R1b/disable-plugin-dot15d4/packet_dot15d4_types.cc0000664000175000017500000000305612124602454024006 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "packet_dot15d4.h" const char *dot15d4_type_str[] = { "802.15.4 Beacon", "802.15.4 Data", "802.15.4 Ack", "802.15.4 Command" }; const char *dot15d4_cmd_subtype_str[] = { "802.15.4 Cmd Association Request", "802.15.4 Cmd Association Response", "802.15.4 Cmd Disassociation", "802.15.4 Cmd Data Request", "802.15.4 Cmd PAN ID Conflict", "802.15.4 Cmd Orphan Notification", "802.15.4 Cmd Beacon Request", "802.15.4 Cmd Coordinator Realign", "802.15.4 Cmd GTS Request" }; const char *dot15d4_crypt_type_str[] = { "No encryption", "No encryption, 32-bit MIC", "No encryption, 64-bit MIC", "No encryption, 128-bit MIC", "Encrypted", "Encrypted, 32-bit MIC", "Encrypted, 64-bit MIC", "Encrypted, 128-bit MIC" }; kismet-2013-03-R1b/disable-plugin-dot15d4/packetsource_raven.h0000664000175000017500000000603012124602454023567 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_RAVEN_H__ #define __PACKETSOURCE_RAVEN_H__ #include "config.h" #ifdef SYS_LINUX #include #include #include #define USE_PACKETSOURCE_RAVEN class PacketSource_Raven : public KisPacketSource { public: PacketSource_Raven() { fprintf(stderr, "FATAL OOPS: Packetsource_Raven()\n"); exit(1); } PacketSource_Raven(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Raven(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("raven", this, "IEEE802154", 0); return 1; } PacketSource_Raven(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Raven(); virtual int ParseOptions(vector *in_opts); virtual int OpenSource(); virtual int CloseSource(); virtual int FetchChannelCapable() { return 1; } virtual int EnableMonitor() { return 1; } virtual int DisableMonitor() { return 1; } // We seem to crash the default & killerbee firmwares if we hop more rapidly // than 3 times a second, throttle us. virtual int FetchChannelMaxVelocity() { return 3; } virtual int SetChannel(unsigned int in_ch); virtual int FetchDescriptor(); virtual int Poll(); struct raven_pkt { char *data; int len; int channel; }; protected: virtual void FetchRadioData(kis_packet *in_packet) { }; int d154_packet_id; int thread_active; /* Screw libusb and their crappy IO options - libusb 0.12 API, no * async IO ... libusb 1.x, async io can't be used in plugins and contaminates * all of the select loop code which makes it impossible to use in plugins */ pthread_t cap_thread; pthread_mutex_t packet_lock, device_lock; // Named USB interface string usb_dev; struct usb_dev_handle *devhdl; // FD pipes int fake_fd[2]; // Packet storage, locked with packet_lock vector packet_queue; // Pending packet, locked with packet_lock int pending_packet; // Error from thread string thread_error; friend void *raven_cap_thread(void *); }; #endif #endif kismet-2013-03-R1b/disable-plugin-dot15d4/packet_dot15d4.h0000664000175000017500000000651012124602454022422 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKET_DOT15D4_H__ #define __PACKET_DOT15D4_H__ #include "config.h" #include #include #include #include // Kismet DLT for 15.4 #define KDLT_IEEE802_15_4 195 // three-bit frametype #define DOT154_FH_FRAMETYPE(f) ((f) & 0x07) // single bits #define DOT154_FH_SECURITY(f) ((f) & 0x08) #define DOT154_FH_PENDING(f) ((f) & 0x10) #define DOT154_FH_ACKREQ(f) ((f) & 0x20) #define DOT154_FH_INTRAPAN(f) ((f) & 0x40) // two-bit values #define DOT154_DESTADDRMODE_MASK 0x3072 #define DOT154_FRAMEVERSION_MASK 0x12288 #define DOT154_SOURCEADDRMODE_MASK 0x49152 #define DOT154_FH_DESTADDRMODE(f) ((unsigned int) ((f) & 0x0C00) >> 10) #define DOT154_FH_FRAMEVERSION(f) ((unsigned int) ((f) & 0x3000) >> 12) #define DOT154_FH_SRCADDRMODE(f) ((unsigned int) ((f) & 0xC000) >> 14) #define DOT154_FH_ADDR_NONE 0x0000 #define DOT154_FH_ADDR_SHORT 0x0002 #define DOT154_FH_ADDR_LONG 0x0003 int kis_dot15d4_dissector(CHAINCALL_PARMS); enum dot15d4_type { d15d4_type_beacon = 0x00, d15d4_type_data = 0x01, d15d4_type_ack = 0x02, d15d4_type_command = 0x03, d15d4_type_max }; extern const char *dot15d4_type_str[]; enum dot15d4_cmd_subtype { d15d4_subtype_cmd_assocreq = 0x01, d15d4_subtype_cmd_assocresp = 0x02, d15d4_subtype_cmd_disassoc = 0x03, d15d4_subtype_cmd_datareq = 0x04, d15d4_subtype_cmd_panconf = 0x05, d15d4_subtype_cmd_orphan = 0x06, d15d4_subtype_cmd_beaconreq = 0x07, d15d4_subtype_cmd_coordrealign = 0x08, d15d4_subtype_cmd_gtsreq = 0x09, d15d4_subtype_cmd_max }; extern const char *dot15d4_cmd_subtype_str[]; enum dot15d4_crypt_type { d15d4_crypt_none = 0x00, d15d4_crypt_mic32 = 0x01, d15d4_crypt_mic64 = 0x02, d15d4_crypt_mic126 = 0x03, d15d4_crypt_enc = 0x04, d15d4_crypt_enc_mic32 = 0x05, d15d4_crypt_enc_mic64 = 0x06, d15d4_crypt_enc_mic128 = 0x07, d15d4_crypt_max }; extern const char *dot15d4_crypt_type_str[]; class dot15d4_packinfo : public packet_component { public: dot15d4_packinfo() { self_destruct = 1; frame_header = 0; type = 0; security = 0; sourceaddr_mode = 0; destaddr_mode = 0; version = 0; seqno = 0; source_addr = 0; dest_addr = 0; source_pan = 0; dest_pan = 0; intrapan = 0; crypt = 0; channel = 0; uint8_t *data; int data_len; }; uint16_t frame_header; unsigned int type; unsigned int security; unsigned int sourceaddr_mode; unsigned int destaddr_mode; unsigned int version; unsigned int intrapan; unsigned int seqno; unsigned int source_pan, dest_pan; // 2 or 8 bytes depending uint64_t source_addr; uint64_t dest_addr; unsigned int crypt; int channel; }; #endif kismet-2013-03-R1b/disable-plugin-dot15d4/kismet_dot15d4.cc0000664000175000017500000001022112124602454022577 0ustar dragorndragorn/* This file is part of Kismet This file was derived directly from aircrack-ng, and most of the other files in this directory come, almost unmodified, from that project. For more information about aircrack-ng, visit: http://aircrack-ng.org Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. * If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. * If you do not wish to do so, delete this exception statement from your version. * If you delete this exception statement from all source files in the program, then also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packetsource_raven.h" #include "packetsource_serialdev.h" #include "packet_dot15d4.h" #include "tracker_dot15d4.h" GlobalRegistry *globalreg = NULL; int pack_comp_dot15d4; int dot15d4_unregister(GlobalRegistry *in_globalreg) { return 0; } int dot15d4_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; globalreg->sourcetracker->AddChannelList("IEEE802154:11,12,13,14,15,16," "17,18,19,20,21,22,23,24,25,26"); #ifdef USE_PACKETSOURCE_RAVEN if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Raven(globalreg)) < 0 || globalreg->fatal_condition) return -1; #endif #ifdef USE_PACKETSOURCE_SERIALDEV if (globalreg->sourcetracker->RegisterPacketSource(new PacketSource_Serialdev(globalreg)) < 0 || globalreg->fatal_condition) return -1; #endif globalreg->packetchain->RegisterHandler(&kis_dot15d4_dissector, NULL, CHAINPOS_LLCDISSECT, 1); pack_comp_dot15d4 = globalreg->packetchain->RegisterPacketComponent("DOT15D4FRAME"); // dumpfile that inherits from the global one Dumpfile_Pcap *dot15d4dump; dot15d4dump = new Dumpfile_Pcap(globalreg, "pcap15d4", KDLT_IEEE802_15_4, globalreg->pcapdump, NULL, NULL); dot15d4dump->SetVolatile(1); // Tracker Tracker_Dot15d4 *track15d4 = new Tracker_Dot15d4(globalreg); return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "DOT15D4"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "802.15.4 protocol plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = dot15d4_register; data->plugin_unregister = dot15d4_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } kismet-2013-03-R1b/disable-plugin-dot15d4/packet_dot15d4.cc0000664000175000017500000000752612124602454022570 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include "packet_dot15d4.h" // From kismet_dot15d4 extern int pack_comp_dot15d4; static int debugno = 0; int kis_dot15d4_dissector(CHAINCALL_PARMS) { int offset = 0; dot15d4_packinfo *pi = NULL; if (in_pack->error) return 0; kis_datachunk *chunk = (kis_datachunk *) in_pack->fetch(_PCM(PACK_COMP_LINKFRAME)); if (chunk == NULL) return 0; if (chunk->dlt != KDLT_IEEE802_15_4) return 0; debugno++; if (chunk->length < 11) { _MSG("Short dot15d4 frame!", MSGFLAG_ERROR); in_pack->error = 1; return 0; } pi = new dot15d4_packinfo(); uint16_t fh; fh = kis_letoh16(*((uint16_t *) chunk->data)); pi->frame_header = fh; pi->type = DOT154_FH_FRAMETYPE(fh); pi->security = DOT154_FH_SECURITY(fh); pi->sourceaddr_mode = DOT154_FH_SRCADDRMODE(fh); pi->destaddr_mode = DOT154_FH_DESTADDRMODE(fh); pi->version = DOT154_FH_FRAMEVERSION(fh); pi->intrapan = DOT154_FH_INTRAPAN(fh); #if 0 printf("Packet %d FH: %4.04x\n", debugno, fh); printf(" Frame Type : %d\n", DOT154_FH_FRAMETYPE(fh)); printf(" Frame Security: %d\n", DOT154_FH_SECURITY(fh)); printf(" Frame SA Mode : %u\n", DOT154_FH_SRCADDRMODE(fh)); printf(" Frame Version : %u\n", DOT154_FH_FRAMEVERSION(fh)); #endif pi->seqno = chunk->data[2]; offset = 3; if (pi->type == d15d4_type_beacon) { if (chunk->length < offset + 2) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->source_pan), &(chunk->data[offset]), 2); offset += 2; if (pi->sourceaddr_mode == DOT154_FH_ADDR_LONG) { if (chunk->length < offset + 8) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->source_addr), &(chunk->data[offset]), 8); offset += 8; } else { if (chunk->length < offset + 2) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->source_addr), &(chunk->data[offset]), 2); offset += 2; } } if (pi->type == d15d4_type_data || pi->type == d15d4_type_command) { if (chunk->length < offset + 2) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->dest_pan), &(chunk->data[offset]), 2); offset += 2; if (pi->destaddr_mode == DOT154_FH_ADDR_LONG) { if (chunk->length < offset + 8) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->dest_addr), &(chunk->data[offset]), 8); offset += 8; } else { if (chunk->length < offset + 2) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->dest_addr), &(chunk->data[offset]), 2); offset += 2; } if (pi->intrapan == 0) { memcpy(&(pi->source_pan), &(chunk->data[offset]), 2); offset += 2; } if (pi->sourceaddr_mode == DOT154_FH_ADDR_LONG) { if (chunk->length < offset + 8) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->source_addr), &(chunk->data[offset]), 8); offset += 8; } else { if (chunk->length < offset + 2) { delete pi; in_pack->error = 1; return 0; } memcpy(&(pi->source_addr), &(chunk->data[offset]), 2); offset += 2; } } in_pack->insert(pack_comp_dot15d4, pi); return 1; } kismet-2013-03-R1b/disable-plugin-dot15d4/tracker_dot15d4.cc0000664000175000017500000001177112124602454022751 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include "packet_dot15d4.h" #include "tracker_dot15d4.h" extern int pack_comp_dot15d4; enum D15D4DEV_fields { D15D4DEV_srcaddr, D15D4DEV_dstaddr, D15D4DEV_srcpan, D15D4DEV_dstpan, D15D4DEV_crypt, D15D4DEV_channel, D15D4DEV_firsttime, D15D4DEV_lasttime, D15D4DEV_packets, D15D4DEV_beacons, D15D4DEV_data, D15D4DEV_cmd, D15D4DEV_maxfield }; const char *D15D4DEV_fields_text[] = { "srcaddr", "dstaddr", "srcpan", "dstpan", "crypt", "channel", "firsttime", "lasttime", "packets", "beacons", "data", "command", NULL }; int Protocol_D15D4DEV(PROTO_PARMS) { dot15d4_network *net = (dot15d4_network *) data; ostringstream osstr; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= D15D4DEV_maxfield) { out_string = "Unknown field requested."; return -1; } osstr.str(""); if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case D15D4DEV_srcaddr: // TODO - fix these for endian swaps, output as bytes in a fixed order osstr << net->netid.source_addr; break; case D15D4DEV_dstaddr: // TODO - fix these for endian swaps, output as bytes in a fixed order osstr << net->netid.dest_addr; break; case D15D4DEV_srcpan: osstr << net->netid.source_pan; break; case D15D4DEV_dstpan: osstr << net->netid.dest_pan; break; case D15D4DEV_crypt: osstr << net->netid.crypt; break; case D15D4DEV_channel: osstr << net->netid.channel; break; case D15D4DEV_firsttime: osstr << net->first_time; break; case D15D4DEV_lasttime: osstr << net->last_time; break; case D15D4DEV_packets: osstr << net->num_packets; break; case D15D4DEV_beacons: osstr << net->num_beacons; break; case D15D4DEV_data: osstr << net->num_data; break; case D15D4DEV_cmd: osstr << net->num_cmd; break; } out_string += osstr.str() + " "; cache->Cache(fnum, osstr.str()); } return 1; } void Protocol_D15D4DEV_enable(PROTO_ENABLE_PARMS) { ((Tracker_Dot15d4 *) data)->BlitDevices(in_fd); } int d15tracktimer(TIMEEVENT_PARMS) { ((Tracker_Dot15d4 *) parm)->BlitDevices(-1); return 1; } int dot15d4_chain_hook(CHAINCALL_PARMS) { return ((Tracker_Dot15d4 *) auxdata)->chain_handler(in_pack); } Tracker_Dot15d4::Tracker_Dot15d4(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; globalreg->packetchain->RegisterHandler(&dot15d4_chain_hook, this, CHAINPOS_CLASSIFIER, 0); D15D4DEV_ref = globalreg->kisnetserver->RegisterProtocol("D15D4DEV", 0, 1, D15D4DEV_fields_text, &Protocol_D15D4DEV, &Protocol_D15D4DEV_enable, this); timer_ref = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &d15tracktimer, this); } int Tracker_Dot15d4::chain_handler(kis_packet *in_pack) { dot15d4_packinfo *d15d4 = (dot15d4_packinfo *) in_pack->fetch(pack_comp_dot15d4); if (d15d4 == NULL) return 0; dot15d4_network_id netid(d15d4); dot15d4_network *net = NULL; map::iterator titr = tracked_devs.find(netid); if (titr == tracked_devs.end()) { net = new dot15d4_network(); net->first_time = globalreg->timestamp.tv_sec; net->netid = netid; tracked_devs[netid] = net; } else { net = titr->second; } net->dirty = 1; net->last_time = globalreg->timestamp.tv_sec; net->num_packets++; if (d15d4->type == d15d4_type_beacon) { net->num_beacons++; } else if (d15d4->type == d15d4_type_data) { net->num_data++; } else if (d15d4->type == d15d4_type_command) { net->num_cmd++; } return 1; } void Tracker_Dot15d4::BlitDevices(int in_fd) { map::iterator x; for (x = tracked_devs.begin(); x != tracked_devs.end(); x++) { kis_protocol_cache cache; if (in_fd == -1) { if (x->second->dirty == 0) continue; x->second->dirty = 0; if (globalreg->kisnetserver->SendToAll(D15D4DEV_ref, (void *) x->second) < 0) break; } else { if (globalreg->kisnetserver->SendToClient(in_fd, D15D4DEV_ref, (void *) x->second, &cache) < 0) break; } } } kismet-2013-03-R1b/disable-plugin-dot15d4/packetsource_serialdev.cc0000664000175000017500000002514112124602454024574 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "packetsource_serialdev.h" #include "packet_dot15d4.h" d15d4_serialdev_helper::d15d4_serialdev_helper(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { sercli = NULL; netclient = NULL; } int d15d4_serialdev_helper::OpenSerialDev(string in_dev) { sercli = new SerialClient(globalreg); netclient = sercli; device = in_dev; // fprintf(stderr, "debug - serialdev helper for %s\n", in_dev.c_str()); RegisterNetworkClient(sercli); sercli->RegisterClientFramework(this); return Reconnect(); } d15d4_serialdev_helper::~d15d4_serialdev_helper() { globalreg->RemovePollableSubsys(this); } int d15d4_serialdev_helper::Shutdown() { if (sercli != NULL) { sercli->FlushRings(); sercli->KillConnection(); } return 1; } int d15d4_serialdev_helper::Reconnect() { if (sercli->Connect(device.c_str(), 0, NULL, NULL) < 0) { _MSG("d15d4 serialdev: could not open serial port " + string(device), MSGFLAG_ERROR); return 0; } struct termios options; sercli->GetOptions(&options); options.c_cflag |= (CLOCAL | CREAD); options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); sercli->SetOptions(TCSANOW, &options); sercli->FlushSerial(TCIFLUSH); // sercli->SetBaud(B115200); state = 1; s_id = s_len = s_rlen = s_status = s_level = -1; return 1; } int d15d4_serialdev_helper::SendCommand(uint8_t *command, unsigned int in_len, uint8_t *in_data) { if (sercli == NULL) return 0; uint8_t *cmd = new uint8_t[3 + in_len]; memcpy(cmd, command, 3); if (in_len != 0) memcpy(cmd + 3, in_data, in_len); return sercli->WriteData(cmd, in_len + 3); } int d15d4_serialdev_helper::ParseData() { int len, rlen; char *buf; if (netclient == NULL) return 0; if (netclient->Valid() == 0) return 0; len = netclient->FetchReadLen(); buf = new char[len + 1]; if (netclient->ReadData(buf, len, &rlen) < 0) { _MSG("d15d4 serialdev failed to get data from the serial port", MSGFLAG_ERROR); return -1; } netclient->MarkRead(rlen); // fprintf(stderr, "debug - got %d in read state %d\n", rlen, state); buf[len] = '\0'; // State inherited from previous read incase we get a partial for (unsigned int b = 0; b < rlen; b++) { // fprintf(stderr, "debug - %d of %d state %d %x %c\n", b, rlen, state, buf[b], buf[b]); if (state == 1) { if (buf[b] == 'z') { // fprintf(stderr, "debug - serialdev going to stage 2\n"); state = 2; } else if (buf[b] == 0) { // fprintf(stderr, "debug - serialdev resetting to stage 1\n"); // We reset to 1 state = 1; } else { _MSG("d15d4 serialdev got unexpected character " + HexIntToString(buf[b] & 0xFF), MSGFLAG_ERROR); state = 1; } continue; } else if (state == 2) { if (buf[b] == 'b') { // fprintf(stderr, "debug - serialdev going to stage 3\n"); s_id = -1; s_len = -1; s_rlen = 0; s_status = -1; s_level = -1; state = 3; } else if (buf[b] == 0) { // fprintf(stderr, "debug - serialdev resetting from 2 to 1\n"); state = 1; } else { _MSG("d15d4 serialdev got unexpected character " + HexIntToString(buf[b] & 0xFF) + " in state 2", MSGFLAG_ERROR); state = 1; } continue; } else if (state == 3) { // Get the ID and go to state 4, data/length s_id = buf[b] & 0xff; // fprintf(stderr, "debug - serialdev got id %x going to stage 4\n", s_id); state = 4; continue; } else if (state == 4) { if (s_id == SERIALDEV_RESP_ED) { // fprintf(stderr, "debug - serialdev ED %d %d\n", s_status, s_level); // ID STATUS LEVEL if (s_status < 0) { s_status = buf[b] & 0xff; } else if (s_level < 0) { s_level = buf[b] & 0xff; state = 1; // fprintf(stderr, "debug - serialdev ED %d %d\n", s_status, s_level); // fprintf(stderr, "debug - got ed, going to 1\n"); } } else if (s_id == SERIALDEV_RESP_RECVBLOCK) { // fprintf(stderr, "debug - serialdev BLOCK %d %d\n", s_level, s_len); // ID LQ LEN buf[] if (s_level < 0) { // fprintf(stderr, "debug - getting level\n"); s_level = buf[b] & 0xff; } else if (s_len < 0) { // fprintf(stderr, "debug - getting len\n"); s_len = buf[b] & 0xff; s_rlen = 0; if (s_len > D15D4_MAX_MTU) _MSG("d15d4 serialdev got invalid length in d15d4 chunk", MSGFLAG_ERROR); } else { if (s_rlen < D15D4_MAX_MTU) pkt_data[s_rlen] = buf[b] & 0xff; s_rlen++; if (s_rlen >= s_len) { state = 1; fprintf(stderr, "debug - serialdev got a packet len %d ", s_len); for (unsigned int zz = 0; zz < s_rlen; zz++) { fprintf(stderr, "%02x ", pkt_data[zz]); } fprintf(stderr, "\n"); packetsource->QueuePacket(s_len, pkt_data, s_level); } } } else { // fprintf(stderr, "debug - serialdev generic id %x status %d\n", s_id, s_status); if (s_status < 0) s_status = buf[b] & 0xff; // fprintf(stderr, "debug - %x got status %x going to state 1\n", s_id, s_status); state = 1; } continue; } } delete[] buf; return 1; } PacketSource_Serialdev::PacketSource_Serialdev(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { fake_fd[0] = -1; fake_fd[1] = -1; d154_packet_id = globalreg->packetchain->RegisterPacketComponent("IEEE802_15_4"); serialport = "/dev/ttyUSB1"; helper = new d15d4_serialdev_helper(globalreg); helper->AddPacketsource(this); ParseOptions(in_opts); } PacketSource_Serialdev::~PacketSource_Serialdev() { CloseSource(); if (helper != NULL) { helper->Shutdown(); delete helper; } } int PacketSource_Serialdev::ParseOptions(vector *in_opts) { KisPacketSource::ParseOptions(in_opts); fprintf(stderr, "debug - serialdev parseoptions\n"); if (FetchOpt("device", in_opts) != "") { serialport = FetchOpt("device", in_opts); } _MSG("Serialdev 802.15.4 using device '" + serialport + "'", MSGFLAG_INFO); return 1; } int PacketSource_Serialdev::AutotypeProbe(string in_device) { // Shortcut like we do on airport if (in_device == "d15d4serial") { type = "d15d4serial"; return 1; } return 0; } int PacketSource_Serialdev::OpenSource() { int ret; fprintf(stderr, "debug - serialdev open helper %p device %s\n", helper, serialport.c_str()); ret = helper->OpenSerialDev(serialport); fprintf(stderr, "debug - serialdev open ret %d\n", ret); if (ret < 0) return ret; if (pipe(fake_fd) < 0) { _MSG("Serialdev 802.15.4 '" + name + "' failed to make a pipe() (this is " "really weird): " + string(strerror(errno)), MSGFLAG_ERROR); return 0; } uint8_t cbuf[1]; // Send close, then re-open helper->SendCommand(SERIALDEV_CMD_CLOSE, 0, NULL); helper->SendCommand(SERIALDEV_CMD_OPEN, 0, NULL); // cbuf[0] = 1; // helper->SendCommand(SERIALDEV_CMD_SETCHAN, 1, cbuf); cbuf[0] = SERIALDEV_MODE_RX; helper->SendCommand(SERIALDEV_CMD_SETSTATE, 1, cbuf); pending_packet = 0; return ret; } int PacketSource_Serialdev::CloseSource() { if (fake_fd[0] >= 0) { close(fake_fd[0]); fake_fd[0] = -1; } if (fake_fd[1] >= 0) { close(fake_fd[1]); fake_fd[1] = -1; } if (helper != NULL) { helper->Shutdown(); } return 1; } int PacketSource_Serialdev::SetChannel(unsigned int in_ch) { uint8_t cbuf[1]; // fprintf(stderr, "debug - set channel %u\n", in_ch); if (helper == NULL) return 0; cbuf[0] = (uint8_t) in_ch - 10; helper->SendCommand(SERIALDEV_CMD_SETCHAN, 1, cbuf); last_channel = in_ch; return 1; } int PacketSource_Serialdev::FetchDescriptor() { return fake_fd[0]; } int PacketSource_Serialdev::Poll() { char rx; // Consume the junk byte we used to raise the FD high read(fake_fd[0], &rx, 1); pending_packet = 0; for (unsigned int x = 0; x < packet_queue.size(); x++) { kis_packet *newpack = globalreg->packetchain->GeneratePacket(); newpack->ts.tv_sec = packet_queue[x]->ts.tv_sec; newpack->ts.tv_usec = packet_queue[x]->ts.tv_usec; kis_datachunk *rawchunk = new kis_datachunk; rawchunk->length = packet_queue[x]->len; // Allocated during addpacket, freed during packet destruction, so // we just copy the ptr here rawchunk->data = packet_queue[x]->data; rawchunk->source_id = source_id; rawchunk->dlt = KDLT_IEEE802_15_4; newpack->insert(_PCM(PACK_COMP_LINKFRAME), rawchunk); printf("debug - Got packet chan %d len=%d\n", packet_queue[x]->channel, packet_queue[x]->len); // Flag the header kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = this; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); num_packets++; globalreg->packetchain->ProcessPacket(newpack); // Delete the temp struct, NOT the data delete packet_queue[x]; } // Flush the queue packet_queue.clear(); // printf("debug - packet queue cleared %d\n", packet_queue.size()); return 1; } void PacketSource_Serialdev::QueuePacket(unsigned int in_len, uint8_t *in_data, unsigned int in_sig) { if (packet_queue.size() > 20) { _MSG("d15d4_serialdev packet queue > 20 packets w/out pickup, something " "is acting weird", MSGFLAG_ERROR); return; } struct PacketSource_Serialdev::serial_pkt *rpkt = new PacketSource_Serialdev::serial_pkt; rpkt->sig_lq = in_sig; rpkt->len = in_len; rpkt->data = new uint8_t[in_len]; rpkt->ts.tv_sec = globalreg->timestamp.tv_sec; rpkt->ts.tv_usec = globalreg->timestamp.tv_usec; rpkt->channel = last_channel; memcpy(rpkt->data, in_data, in_len); packet_queue.push_back(rpkt); if (pending_packet == 0) { pending_packet = 1; write(fake_fd[1], in_data, 1); } } kismet-2013-03-R1b/disable-plugin-dot15d4/packetsource_serialdev.h0000664000175000017500000001232312124602454024434 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_SERIALDEV_H__ #define __PACKETSOURCE_SERIALDEV_H__ #include "config.h" #include #include #include #include #define USE_PACKETSOURCE_SERIALDEV // All commands are 3 bytes #define SERIALDEV_CMD_OPEN ((uint8_t *) "zb\x01") #define SERIALDEV_CMD_CLOSE ((uint8_t *) "zb\x02") #define SERIALDEV_CMD_SETCHAN ((uint8_t *) "zb\x04") #define SERIALDEV_CMD_ED ((uint8_t *) "zb\x05") #define SERIALDEV_CMD_CCA ((uint8_t *) "zb\x06") #define SERIALDEV_CMD_SETSTATE ((uint8_t *) "zb\x07") #define SERIALDEV_CMD_XMITDATA ((uint8_t *) "zb\x09") #define SERIALDEV_CMD_RECV ((uint8_t *) "zb\x0b") #define SERIALDEV_STATUS_SUCCESS 0 #define SERIALDEV_STATUS_RX_ON 1 #define SERIALDEV_STATUS_TX_ON 2 #define SERIALDEV_STATUS_TRX_OFF 3 #define SERIALDEV_STATUS_IDLE 4 #define SERIALDEV_STATUS_BUSY 5 #define SERIALDEV_STATUS_BUSY_RX 6 #define SERIALDEV_STATUS_BUSY_TX 7 #define SERIALDEV_STATUS_ERR 8 // u8 id u8 status #define SERIALDEV_RESP_OPEN 0x81 // u8 id u8 status #define SERIALDEV_RESP_CLOSE 0x82 // u8 id u8 status #define SERIALDEV_RESP_SETCHAN 0x84 // u8 id u8 status u8 level #define SERIALDEV_RESP_ED 0x85 // u8 id u8 status #define SERIALDEV_RESP_CCA 0x86 // u8 id u8 status #define SERIALDEV_RESP_SETSTATE 0x87 // u8 id u8 status #define SERIALDEV_RESP_XMITDATA 0x89 // u8 id u8 lq u8 len u8 data[] #define SERIALDEV_RESP_RECVBLOCK 0x8b // u8 id u8 c #define SERIALDEV_RESP_RECVSTREAM 0x8c #define SERIALDEV_MODE_IDLE 0x00 #define SERIALDEV_MODE_RX 0x02 #define SERIALDEV_MODE_TX 0x03 #define D15D4_MAX_MTU 127 class PacketSource_Serialdev; class d15d4_serialdev_helper : public ClientFramework { public: d15d4_serialdev_helper() { fprintf(stderr, "FATAL OOPS: serialdev_helper\n"); exit(1); } d15d4_serialdev_helper(GlobalRegistry *in_globalreg); virtual ~d15d4_serialdev_helper(); int OpenSerialDev(string in_dev); virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set& in_rset, fd_set& in_wset) { return netclient->Poll(in_rset, in_wset); } virtual int ParseData(); virtual int Shutdown(); virtual int Reconnect(); virtual void AddPacketsource(PacketSource_Serialdev *in_src) { packetsource = in_src; } virtual int SendCommand(uint8_t *command, unsigned int in_len, uint8_t *in_data); protected: SerialClient *sercli; PacketSource_Serialdev *packetsource; string device; // Asynch states of current ID, length, etc int state, s_id, s_len, s_rlen, s_status, s_level; // States: // 1 - 'z' // 2 - 'b' // 3 - id // 4 - id subhandler // Data (packets are small). uint8_t pkt_data[D15D4_MAX_MTU]; }; class PacketSource_Serialdev : public KisPacketSource { public: PacketSource_Serialdev() { fprintf(stderr, "FATAL OOPS: Packetsource_Serialdev()\n"); exit(1); } PacketSource_Serialdev(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) { return new PacketSource_Serialdev(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device); virtual int RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("d15d4serial", this, "IEEE802154", 0); return 1; } PacketSource_Serialdev(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts); virtual ~PacketSource_Serialdev(); virtual int ParseOptions(vector *in_opts); virtual int OpenSource(); virtual int CloseSource(); virtual int FetchChannelCapable() { return 1; } virtual int EnableMonitor() { return 1; } virtual int DisableMonitor() { return 1; } // Throttle us to something sane virtual int FetchChannelMaxVelocity() { return 3; } virtual int SetChannel(unsigned int in_ch); virtual int FetchDescriptor(); virtual int Poll(); // This is stupid but i'm tired struct serial_pkt { uint8_t *data; unsigned int len; struct timeval ts; unsigned int channel; unsigned int sig_lq; }; protected: virtual void FetchRadioData(kis_packet *in_packet) { }; virtual void QueuePacket(unsigned int in_len, uint8_t *in_data, unsigned int in_sig); int d154_packet_id; // Serial port to use string serialport; int fake_fd[2]; vector packet_queue; int pending_packet; d15d4_serialdev_helper *helper; friend class d15d4_serialdev_helper; }; #endif kismet-2013-03-R1b/disable-plugin-dot15d4/tracker_dot15d4.h0000664000175000017500000000571512124602454022614 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __TRACKER_DOT15D4_H__ #define __TRACKER_DOT15D4_H__ #include "config.h" #include "globalregistry.h" #include "packet_dot15d4.h" // Since we don't have a mac address we have to identify by other attributes class dot15d4_network_id { public: dot15d4_network_id() { source_addr = dest_addr = 0; source_pan = dest_pan = 0; crypt = 0; channel = 0; } // Build a network for searching out of a packet dot15d4_network_id(dot15d4_packinfo *pack) { dot15d4_network_id(); source_addr = pack->source_addr; dest_addr = pack->dest_addr; source_pan = pack->source_pan; dest_pan = pack->dest_pan; crypt = pack->crypt; channel = pack->channel; } inline dot15d4_network_id operator= (const dot15d4_network_id& in) { source_addr = in.source_addr; dest_addr = in.dest_addr; source_pan = in.source_pan; dest_pan = in.dest_pan; crypt = in.crypt; return *this; } inline bool operator== (const dot15d4_network_id& op) const { if (source_addr == op.source_addr && dest_addr == op.dest_addr && source_pan == op.source_pan && dest_pan == op.dest_pan && crypt == op.crypt && channel == op.channel) { return 1; } return 0; } inline bool operator< (const dot15d4_network_id& op) const { if (source_addr < op.source_addr && dest_addr < op.dest_addr && source_pan < op.source_pan && dest_pan < op.dest_pan && crypt < op.crypt && channel < op.channel) { return 1; } return 0; } uint64_t source_addr, dest_addr; unsigned int source_pan; unsigned int dest_pan; unsigned int crypt; unsigned int channel; }; class dot15d4_network { public: dot15d4_network() { first_time = 0; last_time = 0; num_packets = 0; num_beacons = 0; num_data = 0; num_cmd = 0; dirty = 0; } dot15d4_network_id netid; int num_packets, num_beacons, num_data, num_cmd; time_t first_time, last_time; int dirty; }; class Tracker_Dot15d4 { public: Tracker_Dot15d4() { fprintf(stderr, "FATAL OOPS: tracker_dot15d4()\n"); exit(1); } Tracker_Dot15d4(GlobalRegistry *in_globalreg); int chain_handler(kis_packet *in_pack); void BlitDevices(int in_fd); protected: GlobalRegistry *globalreg; map tracked_devs; int D15D4DEV_ref; int timer_ref; }; #endif kismet-2013-03-R1b/disable-plugin-dot15d4/README0000664000175000017500000001027212124602454020416 0ustar dragorndragornKismet-Dot15d4 0. NOT COMPLETE 1. What is Kismet-Dot15d4 2. Caveats 3. Compiling 4. Installing 5. Using 0. NOT COMPLETE *** THIS CODE IS CURRENTLY NOT COMPLETE *** Unless you're in contact with me and are helping develop it, it's not likely to do what you want. What it CAN do, currently: * Drive the AVR RAVEN * Drive a Linux-Serialdev device via userspace (should work on any platform) * Read pcap files * Print debug info about packets * Log to PCAP file * Do VERY basic 802.15.4 decoding 1. What is Kismet-Dot15d4 Kismet-Dot15d4 is a Kismet plugin which provides 802.15.4 support in Kismet. 802.15.4 is a low-power network protocol for sensors, control, and other "mote" applications, and is the underpinning of Zigbee, 6pan, etc. (Some) Driver support is included for the AVR USB RAVEN board, available here: http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name=ATAVRRZUSBSTICK-ND This driver works only under Linux. Much more complete (and multiplatform) support is included for devices based on the Linux-Serialdev firmware. This is a firmware which allows an 802.15.4 device to be connected via a serial port. Notable devices which support this firmware include the Redbee devices (available from http://redwirellc.com/), and devices based on them, such as the Quahogcon 2010 conference badge and likely the Ninja Networks 2010 Defcon badge. These devices MUST BE FLASHED to use the Linux-Serialdev firmware, firmware and information available at: http://mc1322x.devl.org/ It CAN NOT BE USED with 802.11 wi-fi cards, it is a completely different protocol. Kismet-Dot15d4 defines the decoders, loggers, and UI controls for 802.15.4 networks in a common fashion, and supports reading and writing IEEE802.15.4 pcap files. 2. Caveats This code is currently only partially developed and may not provide full functionality. The Raven code implements a user-space driver using Libusb. Sometimes things go stupid and the card or the server fall down during a sync problem. 3. Compiling Compiling the Kismet-Dot15d4 plugin requires the Kismet source be installed and configured. By default, Kismet-Dot15d4 expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-dot15d4/ KIS_SRC_DIR=/home/foo/src/kismet make For Raven support, the LibUSB library (and development headers, most likely called libusb-devel by your distribution) is required. 4. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-ptw KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-ptw make userinstall 5. Using Once the plugin is loaded, Kismet will automatically understand and decode pcap files with the IEEE802.15.4 link data. To capture from an AVR RAVEN, plug in the USB device, and define a capture source in Kismet using the interface 'raven'. The device will be automatically detected: ncsource=raven To monitor with multiple Raven devices at once, each raven must have a USB device ID specified with the 'usbdev' source option. The definition of the usb device ID depends on the operating system, in Linux it is a number incremented for each device and shown in 'lsusb' and 'dmesg' ncsource=raven:usbdev=... To capture with a Linux-Serialdev device, plug in the usb device, and define a capture source for d15d4serial with a device= option pointing to the USB serial interface. For redbee-based devices, this will be the SECOND serial device registered: ncsource=d15d4serial:device=/dev/ttyUSB1 To enable pcap logging, the logfile must be turned on by adding 'pcap15d4' to the logtypes= line of the kismet.conf. kismet-2013-03-R1b/RELEASENOTES.txt0000664000175000017500000000220712124602454016106 0ustar dragorndragorn2010-07-R1 ---------- Enhancements: Ruby interface and examples Proper TCP Async (for large numbers of drones and other situations) Add hidedata= option for "safer" sniffing in public environments Kluged escape handler for broken ncurses arrow handling on some systems Add --no-root option for zero-priv drone-only deploys Bugfixes: Fix installation on Ubuntu dash IPC updates and fixes for drone IPC architectural fixes 2010-01-R1 ---------- Enhancements: Add basic scanning support (NOT SNIFFING) for bluetooth via BTSCAN plugin Add JSON parsers to accommodate GPSD moving to JSON for all its protocols Add preferredchannels= config file option to delay on chans automatically Allow plugins to append to View, Sort menus Add support for unix domain servers (via Ilya) Sub-menus in UI work with mice Bugfixes: Fix segfault bugs in PTW plugin Fix thread signal stealing in plugins Fix compiling plugins on Snow Leopard Revamp GPS connected logic Fix duplicated callbacks in network handler which lead to wasted CPU and doubled lines on reconnecting to a server Fix GPSD client cancelling own reconnect timer kismet-2013-03-R1b/gpscore.h0000664000175000017500000001506412124602454015274 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __GPSCORE_H__ #define __GPSCORE_H__ #include "config.h" #include "clinetframework.h" #include "tcpclient.h" #include "kis_netframe.h" #include "packetchain.h" // Options #define GPSD_OPT_FORCEMODE 1 enum GPS_fields { GPS_lat, GPS_lon, GPS_alt, GPS_spd, GPS_heading, GPS_fix, GPS_satinfo, GPS_hdop, GPS_vdop, GPS_connected, GPS_maxfield }; struct GPS_data { string lat, lon, alt, spd, heading, mode, satinfo, hdop, vdop, connected; }; int Protocol_GPS(PROTO_PARMS); // GPS info linked into each packet class kis_gps_packinfo : public packet_component { public: kis_gps_packinfo() { self_destruct = 1; // Nothing special, just delete us lat = lon = alt = spd = heading = -1000; hdop = vdop = 0; gps_fix = 0; } double lat; double lon; double alt; double spd; double heading; double hdop, vdop; int gps_fix; }; struct kis_gps_data { kis_gps_data() { gps_valid = 0; // Pick absurd initial values to be clearly out-of-bounds min_lat = 90; max_lat = -90; min_lon = 180; max_lon = -180; min_alt = 100000; max_alt = -100000; min_spd = 100000; max_spd = -100000; add_lat = add_lon = add_alt = 0; aggregate_lat = aggregate_lon = aggregate_alt = 0; aggregate_points = 0; } inline kis_gps_data& operator= (const kis_gps_data& in) { gps_valid = in.gps_valid; min_lat = in.min_lat; min_lon = in.min_lon; max_lat = in.max_lat; max_lon = in.max_lon; min_alt = in.min_alt; max_alt = in.max_alt; min_spd = in.min_spd; max_spd = in.max_spd; aggregate_lat = in.aggregate_lat; aggregate_lon = in.aggregate_lon; aggregate_points = in.aggregate_points; add_lat = in.add_lat; add_lon = in.add_lon; return *this; } inline kis_gps_data& operator+= (const kis_gps_packinfo *in) { if (in->gps_fix >= 2) { gps_valid = 1; if (in->lat < min_lat) min_lat = in->lat; if (in->lon < min_lon) min_lon = in->lon; if (in->alt < min_alt) min_alt = in->alt; if (in->spd < min_spd) min_spd = in->spd; if (in->lat > max_lat) max_lat = in->lat; if (in->lon > max_lon) max_lon = in->lon; if (in->alt > max_alt) max_alt = in->alt; if (in->spd > max_spd) max_spd = in->spd; // Add as fixed to prevent massive precision drift add_lat += double_to_fixed3_7(in->lat); add_lon += double_to_fixed3_7(in->lon); add_alt += double_to_fixed6_4(in->alt); aggregate_points++; aggregate_lat = fixed3_7_to_double(add_lat / aggregate_points); aggregate_lon = fixed3_7_to_double(add_lon / aggregate_points); aggregate_alt = fixed6_4_to_double(add_alt / aggregate_points); } return *this; } inline kis_gps_data& operator+= (const kis_gps_data& in) { if (in.gps_valid == 0) return *this; if (in.min_lat < min_lat) min_lat = in.min_lat; if (in.max_lat > max_lat) max_lat = in.max_lat; if (in.min_lon < min_lon) min_lon = in.min_lon; if (in.max_lon > max_lon) max_lon = in.max_lon; if (in.min_alt < min_alt) min_alt = in.min_alt; if (in.max_alt > max_alt) max_alt = in.max_alt; if (in.min_spd < min_spd) min_spd = in.min_spd; if (in.max_spd > max_spd) max_spd = in.max_spd; add_lat += in.add_lat; add_lon += in.add_lon; add_alt += in.add_alt; aggregate_points += in.aggregate_points; aggregate_lat = fixed3_7_to_double(add_lat / aggregate_points); aggregate_lon = fixed3_7_to_double(add_lon / aggregate_points); aggregate_alt = fixed6_4_to_double(add_alt / aggregate_points); return *this; } int gps_valid; double min_lat, min_lon, min_alt, min_spd; double max_lat, max_lon, max_alt, max_spd; // Aggregate/avg center position long unsigned int add_lat, add_lon, add_alt; double aggregate_lat, aggregate_lon, aggregate_alt; long aggregate_points; }; // Some nasty hacks for GPS automation in plugins w/out having to rewrite // the same code a dozen times #define GPS_COMMON_FIELDS(h) \ h ## _gpsfixed, \ h ## _minlat, h ## _minlon, h ## _minalt, h ## _minspd, \ h ## _maxlat, h ## _maxlon, h ## _maxalt, h ## _maxspd, \ h ## _agglat, h ## _agglon, h ## _aggalt, h ## _aggpoints #define GPS_COMMON_FIELDS_TEXT \ "gpsfixed", \ "minlat", "minlon", "minalt", "minspd", \ "maxlat", "maxlon", "maxalt", "maxspd", \ "agglat", "agglon", "aggalt", "aggpoints" // Packetchain hook to add GPS data int kis_gpspack_hook(CHAINCALL_PARMS); class GPSCore : public ClientFramework { public: GPSCore(); GPSCore(GlobalRegistry *in_globalreg); virtual ~GPSCore(); int Timer(); void SetOptions(uint32_t in_opt) { gps_options = in_opt; } // Fetch a location int FetchLoc(double *in_lat, double *in_lon, double *in_alt, double *in_spd, double *in_hed, int *mode); // Fetch mode int FetchMode() { return mode; } // Fetch connection int FetchConnected() { return (gps_connected == 1 && last_disconnect == 0); } // Various GPS transformations static double CalcHeading(double in_lat, double in_lon, double in_lat2, double in_lon2); static double CalcRad(double lat); static double Rad2Deg(double x); static double Deg2Rad(double x); static double EarthDistance(double in_lat, double in_lon, double in_lat2, double in_lon2); virtual int Reconnect() = 0; struct sat_pos { int prn; int elevation; int azimuth; int snr; }; protected: uint32_t gps_options; int reconnect_attempt; time_t last_disconnect; double lat, lon, alt, spd, hed, hdop, vdop; int mode, gps_ever_lock; int gps_connected; // Last location used for softheading calcs double last_lat, last_lon, last_hed; // Satellite position info map sat_pos_map; map sat_pos_map_tmp; // Scan options & register systems int ScanOptions(); int RegisterComponents(); // network proto ref int gps_proto_ref; int gpseventid; friend int GpsInjectEvent(TIMEEVENT_PARMS); }; #endif kismet-2013-03-R1b/packetsource_airpcap.cc0000664000175000017500000002015012124602454020147 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #if defined(HAVE_LIBPCAP) && defined(HAVE_LIBAIRPCAP) && defined(SYS_CYGWIN) #include "packetsource_airpcap.h" #include #include #include #include "packetsourcetracker.h" // Work around broken pcap.h on cygwin... this is a TERRIBLE THING TO DO but // libwpcap on the airpcap cd seems to come with a pcap.h header for standard // pcap, while the lib contains this symbol. #if defined(HAVE_PCAP_GETEVENT) int pcap_event(pcap_t *); #endif // Prototypes of Windows-specific pcap functions. // wpcap.dll contains these functions, but they are not exported to cygwin because // cygwin doesn't "officially" support the Windows extensions. These functions, // however, are safe to use. extern "C" PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); extern "C" HANDLE pcap_getevent (pcap_t *p); extern "C" int pcap_setmintocopy (pcap_t *p, int size); int PacketSource_AirPcap::OpenSource() { char errstr[STATUS_MAX] = ""; char *unconst = strdup(interface.c_str()); pd = pcap_open_live(unconst, MAX_PACKET_LEN, 1, 1000, errstr); free(unconst); if (strlen(errstr) > 0) { _MSG(errstr, MSGFLAG_PRINTERROR); return -1; } paused = 0; errstr[0] = '\0'; num_packets = 0; if (DatalinkType() < 0) { pcap_close(pd); return -1; } // Fetch the airpcap handle if ((airpcap_handle = pcap_get_airpcap_handle(pd)) == NULL) { _MSG("Adapter " + interface + " does not have airpcap wireless " "extensions", MSGFLAG_PRINTERROR); pcap_close(pd); return -1; } // Tell the adapter to only give us packets which pass internal // FCS validation. All we do is throw away frames which do not, // so theres no reason to add the overhead of locally processing // the checksum. if (!AirpcapSetFcsValidation(airpcap_handle, AIRPCAP_VT_ACCEPT_CORRECT_FRAMES)) { _MSG("Airpcap adapter " + interface + " failed setting FCS " "validation: " + StrStrip((const char *) AirpcapGetLastError(airpcap_handle)), MSGFLAG_PRINTERROR); pcap_close(pd); return -1; } // Add it to the Handle to FD mangler fd_mangle.AddHandle(pcap_getevent(pd)); fd_mangle.Activate(); return 0; } int PacketSource_AirPcap::Poll() { int ret; if ((ret = PacketSource_Pcap::Poll()) == 0) { fd_mangle.Reset(); fd_mangle.Signalread(); } return ret; } int PacketSource_AirPcap::AutotypeProbe(string in_device) { pcap_if_t *alldevs, *d; char errbuf[1024]; if (in_device == "airpcap" || in_device == "airpcap_ask") { type = "airpcap"; return 1; } if (pcap_findalldevs(&alldevs, errbuf) == -1) { _MSG("AirPcapSource failed to find pcap devices: " + string(errbuf), MSGFLAG_PRINTERROR); return 0; } for (d = alldevs; d != NULL; d = d->next) { if (string(d->name) == in_device) { type = "airpcap"; return 1; } } return 0; } int PacketSource_AirPcap::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("airpcap", this, "IEEE80211b", 0); tracker->RegisterPacketProto("airpcap_ask", this, "IEEE80211b", 0); return 1; } PacketSource_AirPcap::PacketSource_AirPcap(GlobalRegistry *in_globalreg, string in_interface, vector *in_opts) : PacketSource_Pcap(in_globalreg, in_interface, in_opts) { pcap_if_t *alldevs, *d; int i, intnum; char errbuf[1024]; // Look for the first airpcap interface if we're just called "airpcap" if (interface == "airpcap") { if (pcap_findalldevs(&alldevs, errbuf) == -1) { _MSG("AirPcapSource failed to find pcap devices: " + string(errbuf), MSGFLAG_PRINTERROR); return; } i = 0; for (d = alldevs; d != NULL; d = d->next) { if (string(d->name).find("airpcap") != string::npos) { interface = d->name; i = 1; break; } } if (i == 0) { _MSG("AirPcapSource failed to find any device which looked like " "airpcap, if you're SURE you have an airpcap device you'll " "need to specify a device. NOTE: KISMET WILL ONLY WORK WITH " "THE AIRPCAP DEVICES. THIS IS A SPECIFIC PIECE OF HARDWARE. " "IT WILL NOT WORK WITH ANY OTHER CARDS.", MSGFLAG_PRINTERROR); return; } } // Go through the prompting game for 'ask' variant if (type == "airpcap_ask") { if (pcap_findalldevs(&alldevs, errbuf) == -1) { _MSG("AirPcapSource failed to find pcap devices: " + string(errbuf), MSGFLAG_PRINTERROR); return; } fprintf(stdout, "Available interfaces:\n"); for (d = alldevs, i = 0; d != NULL; d = d->next) { fprintf(stdout, "%d. %s\n", ++i, d->name); if (d->description) fprintf(stdout, " %s\n", d->description); else fprintf(stdout, " No description available\n"); } if (i == 0) { pcap_freealldevs(alldevs); _MSG("airPcapSource failed to find any devices, are " "WinPcap and AirPcap properly installed?", MSGFLAG_PRINTERROR); return; } while (1) { fprintf(stdout, "Enter interface number (1-%d): ", i); if (fscanf(stdin, "%d", &intnum) != 1) { fprintf(stdout, "Invalid entry, expected a number\n"); continue; } if (intnum < 1 || intnum > i) { fprintf(stdout, "Invalid entry, expected between 1 " "and %d\n", i); continue; } break; } // Iterate for (d = alldevs, i = 0; i < intnum - 1; d = d->next, i++) ; interface = string(d->name); pcap_freealldevs(alldevs); } } int PacketSource_AirPcap::EnableMonitor() { // This is handled during the open because we need a working pcap handle return 1; } int PacketSource_AirPcap::DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_CANTUNMON; } int PacketSource_AirPcap::FetchHardwareChannel() { unsigned int ch; if (!AirpcapGetDeviceChannel(airpcap_handle, &ch)) return -1; return (int) ch; } int PacketSource_AirPcap::FetchDescriptor() { return fd_mangle.GetFd(); } int PacketSource_AirPcap::SetChannel(unsigned int in_ch) { if (!AirpcapSetDeviceChannel(airpcap_handle, in_ch)) { _MSG("Airpcap adapter " + interface + " failed setting channel " + IntToString(in_ch) + ": " + StrStrip((const char *) AirpcapGetLastError(airpcap_handle)), MSGFLAG_PRINTERROR); return -1; } return 0; } vector PacketSource_AirPcap::FetchSupportedChannels(string in_interface) { char errstr[STATUS_MAX] = ""; vector ret; unsigned int numchans; AirpcapChannelInfo *channels; string qint = in_interface; pcap_if_t *alldevs, *d; int i; // Look for the first airpcap interface if we're just called "airpcap" if (in_interface == "airpcap") { if (pcap_findalldevs(&alldevs, errstr) == -1) { return ret; } i = 0; for (d = alldevs; d != NULL; d = d->next) { if (string(d->name).find("airpcap") != string::npos) { qint = d->name; i = 1; break; } } if (i == 0) { return ret; } } /* We have to open the device in pcap to get the airpcap handle to * get the channel list. */ pd = pcap_open_live((char *) qint.c_str(), MAX_PACKET_LEN, 1, 1000, errstr); if (strlen(errstr) > 0) { _MSG(errstr, MSGFLAG_PRINTERROR); return ret; } // Fetch the airpcap handle if ((airpcap_handle = pcap_get_airpcap_handle(pd)) == NULL) { pcap_close(pd); return ret; } if (AirpcapGetDeviceSupportedChannels(airpcap_handle, &channels, &numchans) == 0) { pcap_close(pd); return ret; } for (unsigned int x = 0, i = 0; x < numchans; x++) { if (channels[x].Frequency == i) continue; i = channels[x].Frequency; ret.push_back(FreqToChan(channels[x].Frequency)); } pcap_close(pd); return ret; } #endif kismet-2013-03-R1b/configfile.h0000664000175000017500000000553612124602454015742 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __CONFIGFILE_H__ #define __CONFIGFILE_H__ #include "config.h" #include #include #include #include #include #include #include #include #include #include "globalregistry.h" #include "macaddr.h" class ConfigFile { public: ConfigFile(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; checksum = 0; } int ParseConfig(const char *in_fname); int SaveConfig(const char *in_fname); string FetchOpt(string in_key); vector FetchOptVec(string in_key); // Fetch a true/false t/f value with a default (ie value returned if not // equal to true, or missing.) int FetchOptBoolean(string in_key, int dvalue); int FetchOptDirty(string in_key); void SetOptDirty(string in_key, int in_dirty); void SetOpt(string in_key, string in_val, int in_dirty); void SetOptVec(string in_key, vector in_val, int in_dirty); string ExpandLogPath(string path, string logname, string type, int start, int overwrite = 0); // Fetches the load-time checksum of the config values. uint32_t FetchFileChecksum(); protected: GlobalRegistry *globalreg; void CalculateChecksum(); map > config_map; map config_map_dirty; uint32_t checksum; string ckstring; }; // Config file with grouping. Only used at the moment for runtime log file // parsing. Doesn't currently support the 'include = ' statement, either class GroupConfigFile { public: class GroupEntity { public: string name; map > value_map; }; GroupConfigFile() { checksum = 0; root = NULL; } int ParseConfig(const char *in_fname); // Return the vector of entities in this group, or the top groups if NULL vector FetchEntityGroup(GroupEntity *in_parent); string FetchOpt(string in_key, GroupEntity *in_parent); vector FetchOptVec(string in_key, GroupEntity *in_parent); uint32_t FetchFileChecksum(); protected: void CalculateChecksum(); map > parsed_group_map; uint32_t checksum; GroupEntity *root; }; #endif kismet-2013-03-R1b/packet.h0000664000175000017500000002112512124602454015074 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKET_H__ #define __PACKET_H__ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #include "macaddr.h" #include "packet_ieee80211.h" // This is the main switch for how big the vector is. If something ever starts // bumping up against this we'll need to increase it, but that'll slow down // generating a packet (slightly) so I'm leaving it relatively low. #define MAX_PACKET_COMPONENTS 64 // Maximum length of a frame #define MAX_PACKET_LEN 8192 // Same as defined in libpcap/system, but we need to know the basic dot11 DLT // even when we don't have pcap #define KDLT_IEEE802_11 105 // High-level packet component so that we can provide our own destructors class packet_component { public: packet_component() { self_destruct = 1; }; virtual ~packet_component() { } int self_destruct; }; // Overall packet container that holds packet information class kis_packet { public: // Time of packet creation struct timeval ts; // Do we know this is in error from the capture source // itself? int error; // Actual vector of bits in the packet vector content_vec; // Init stuff kis_packet() { error = 0; // Stock and init the content vector content_vec.resize(MAX_PACKET_COMPONENTS, NULL); /* for (unsigned int y = 0; y < MAX_PACKET_COMPONENTS; y++) content_vec[y] = NULL; */ } ~kis_packet() { // Delete everything we contain when we die. I hope whomever put // it there expected this. for (unsigned int y = 0; y < MAX_PACKET_COMPONENTS; y++) { packet_component *pcm = content_vec[y]; if (pcm == NULL) continue; // If it's marked for self-destruction, delete it. Otherwise, // someone else is responsible for removing it. if (pcm->self_destruct) delete pcm; content_vec[y] = NULL; } } inline void insert(const unsigned int index, packet_component *data) { if (index >= MAX_PACKET_COMPONENTS) return; content_vec[index] = data; } inline void *fetch(const unsigned int index) { if (index >= MAX_PACKET_COMPONENTS) return NULL; return content_vec[index]; } inline void erase(const unsigned int index) { if (index >= MAX_PACKET_COMPONENTS) return; // Delete it if we can - both from our array and from // memory. Whatever inserted it had better expect this // to happen or it will be very unhappy if (content_vec[index] != NULL) { if (content_vec[index]->self_destruct) delete content_vec[index]; content_vec[index] = NULL; } } inline packet_component *operator[] (const unsigned int& index) const { if (index >= MAX_PACKET_COMPONENTS) return NULL; return content_vec[index]; } }; // Arbitrary 802.11 data chunk class kis_datachunk : public packet_component { public: uint8_t *data; unsigned int length; int dlt; uint16_t source_id; kis_datachunk() { self_destruct = 1; // Our delete() handles everything data = NULL; length = 0; source_id = 0; } virtual ~kis_datachunk() { delete[] data; length = 0; } }; class kis_fcs_bytes : public packet_component { public: kis_fcs_bytes() { self_destruct = 1; fcs[0] = fcs[1] = fcs[2] = fcs[3] = 0; fcsp = (uint32_t *) fcs; fcsvalid = 0; } uint8_t fcs[4]; uint32_t *fcsp; int fcsvalid; }; // Dot11d struct struct dot11d_range_info { dot11d_range_info() { startchan = 0; numchan = 0; txpower = 0; } int startchan, numchan, txpower; }; // Info from the IEEE 802.11 frame headers for kismet class kis_ieee80211_packinfo : public packet_component { public: kis_ieee80211_packinfo() { self_destruct = 1; // Our delete() handles this corrupt = 0; header_offset = 0; type = packet_unknown; subtype = packet_sub_unknown; mgt_reason_code = 0; ssid_len = 0; ssid_blank = 0; source_mac = mac_addr(0); dest_mac = mac_addr(0); bssid_mac = mac_addr(0); other_mac = mac_addr(0); distrib = distrib_unknown; cryptset = 0; decrypted = 0; fuzzywep = 0; fmsweak = 0; ess = 0; ibss = 0; channel = 0; encrypted = 0; beacon_interval = 0; maxrate = 0; timestamp = 0; sequence_number = 0; frag_number = 0; fragmented = 0; retry = 0; duration = 0; datasize = 0; qos = 0; ssid_csum = 0; dot11d_country = "XXX"; } // Corrupt 802.11 frame int corrupt; // Offset to data components in frame unsigned int header_offset; ieee_80211_type type; ieee_80211_subtype subtype; uint8_t mgt_reason_code; // Raw SSID string ssid; // Length of the SSID header field int ssid_len; // Is the SSID empty spaces? int ssid_blank; // Address set mac_addr source_mac; mac_addr dest_mac; mac_addr bssid_mac; mac_addr other_mac; ieee_80211_disttype distrib; uint64_t cryptset; int decrypted; // Might as well put this in here? int fuzzywep; int fmsweak; // Was it flagged as ess? (ap) int ess; int ibss; // What channel does it report int channel; // Is this encrypted? int encrypted; int beacon_interval; uint16_t qos; // Some cisco APs seem to fill in this info field string beacon_info; double maxrate; uint64_t timestamp; int sequence_number; int frag_number; int fragmented; int retry; int duration; int datasize; uint32_t ssid_csum; string dot11d_country; vector dot11d_vec; }; // some protocols we do try to track enum kis_protocol_info_type { proto_unknown, proto_udp, proto_tcp, proto_arp, proto_dhcp_offer, proto_dhcp_discover, proto_cdp, proto_turbocell, proto_netstumbler_probe, proto_lucent_probe, proto_iapp, proto_leap, proto_ttls, proto_tls, proto_peap, proto_eap_unknown, proto_isakmp, proto_pptp, }; class kis_data_packinfo : public packet_component { public: kis_data_packinfo() { self_destruct = 1; // Safe to delete us proto = proto_unknown; ip_source_port = 0; ip_dest_port = 0; ip_source_addr.s_addr = 0; ip_dest_addr.s_addr = 0; ip_netmask_addr.s_addr = 0; ip_gateway_addr.s_addr = 0; field1 = 0; ivset[0] = ivset[1] = ivset[2] = 0; } kis_protocol_info_type proto; // IP info, we re-use a subset of the kis_protocol_info_type enum to fill // in where we got our IP data from. A little klugey, but really no reason // not to do it int ip_source_port; int ip_dest_port; in_addr ip_source_addr; in_addr ip_dest_addr; in_addr ip_netmask_addr; in_addr ip_gateway_addr; kis_protocol_info_type ip_type; // The two CDP fields we really care about for anything string cdp_dev_id; string cdp_port_id; // DHCP Discover data string discover_host, discover_vendor; // IV uint8_t ivset[3]; // An extra field that can be filled in int field1; }; // Layer 1 radio info record for kismet class kis_layer1_packinfo : public packet_component { public: kis_layer1_packinfo() { self_destruct = 1; // Safe to delete us signal_dbm = noise_dbm = 0; signal_rssi = noise_rssi = 0; carrier = carrier_unknown; encoding = encoding_unknown; datarate = 0; freq_mhz = 0; accuracy = 0; } // How "accurate" are we? Higher == better. Nothing uses this yet // but we might as well track it here. int accuracy; // Frequency seen on int freq_mhz; // Connection info int signal_dbm, signal_rssi; int noise_dbm, noise_rssi; // What carrier brought us this packet? phy_carrier_type carrier; // What encoding? phy_encoding_type encoding; // What data rate? int datarate; // Checksum, if checksumming is enabled; Only of the non-header // data uint32_t content_checkum; }; #endif kismet-2013-03-R1b/kis_panel_frontend.cc0000664000175000017500000005701312124602454017634 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #include #include #include #include #include "util.h" #include "messagebus.h" #include "kis_panel_widgets.h" #include "kis_panel_windows.h" #include "kis_panel_frontend.h" #include "version.h" #define KPI_SOURCE_FIELDS "uuid,interface,type,username,channel,packets,hop," \ "velocity,dwell,hop_time_sec,hop_time_usec,channellist,error,warning" #define KPI_ALERT_FIELDS "sec,usec,header,bssid,source,dest,other,channel,text" // STATUS protocol parser that injects right into the messagebus void KisPanelClient_STATUS(CLIPROTO_CB_PARMS) { if (proto_parsed->size() < 2) { return; } int flags; string text; text = (*proto_parsed)[0].word; if (sscanf((*proto_parsed)[1].word.c_str(), "%d", &flags) != 1) { return; } _MSG(text, flags); } void KisPanelClient_SOURCE(CLIPROTO_CB_PARMS) { // Pass it off to the clinet frame ((KisPanelInterface *) auxptr)->proto_SOURCE(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisPanelClient_ALERT(CLIPROTO_CB_PARMS) { ((KisPanelInterface *) auxptr)->proto_ALERT(globalreg, proto_string, proto_parsed, srccli, auxptr); } void KisPanelClient_INFO(CLIPROTO_CB_PARMS) { ((KisPanelInterface *) auxptr)->proto_INFO(globalreg, proto_string, proto_parsed, srccli, auxptr); } void kpi_prompt_sourcewarnings(KIS_PROMPT_CB_PARMS) { if (check) globalreg->panel_interface->prefs->SetOpt("WARN_SOURCEWARN", "false", 1); } void KisPanelInterface::proto_SOURCE(CLIPROTO_CB_PARMS) { // "uuid,interface,type,username,channel,packets,hop," // "velocity,dwell,hop_time_sec,hop_time_usec,channellist, // error,warning" if (proto_parsed->size() < 14) { return; } int fnum = 0; int tint; knc_card *source = NULL; uuid inuuid = uuid((*proto_parsed)[fnum++].word); if (inuuid.error) return; if (netcard_map.find(inuuid) == netcard_map.end()) { source = new knc_card; source->carduuid = inuuid; source->uuid_hash = Adler32Checksum(inuuid.UUID2String().c_str(), inuuid.UUID2String().length()); netcard_map[inuuid] = source; } else { source = netcard_map.find(inuuid)->second; } source->last_update = time(0); source->interface = ((*proto_parsed)[fnum++].word); source->type = ((*proto_parsed)[fnum++].word); source->name = ((*proto_parsed)[fnum++].word); if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->channel = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->packets = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->hopping = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->hopvelocity = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->dwell = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->hop_tm.tv_sec = tint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) return; source->hop_tm.tv_usec = tint; source->channellist = (*proto_parsed)[fnum++].word; source->error = (*proto_parsed)[fnum++].word == "1"; string warning = (*proto_parsed)[fnum++].word; if (warning != "" && warning != source->warning && prefs->FetchOpt("WARN_SOURCEWARN") != "false") { vector t; t = StrTokenize(InLineWrap(warning, 0, 50), "\n"); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, this); kpp->SetTitle("Sources Warning"); kpp->SetDisplayText(t); kpp->SetCheckText("Do not show source warnings in the future"); kpp->SetChecked(0); kpp->SetDefaultButton(1); kpp->SetButtonText("OK", ""); kpp->SetCallback(kpi_prompt_sourcewarnings, this); QueueModalPanel(kpp); } source->warning = warning; } void KisPanelInterface::proto_ALERT(CLIPROTO_CB_PARMS) { // sec, usec, header, bssid, source, dest, other, channel, text if (proto_parsed->size() < 9) { return; } int fnum = 0; int tint; unsigned int tuint; mac_addr tmac; knc_alert *alert = new knc_alert; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { delete alert; return; } alert->tv.tv_sec = tuint; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) { delete alert; return; } alert->tv.tv_usec = tuint; alert->alertname = MungeToPrintable((*proto_parsed)[fnum++].word); tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete alert; return; } alert->bssid = tmac; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete alert; return; } alert->source = tmac; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete alert; return; } alert->dest = tmac; tmac = mac_addr((*proto_parsed)[fnum++].word.c_str()); if (tmac.error) { delete alert; return; } alert->other = tmac; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) { delete alert; return; } alert->channel = tint; alert->text = (*proto_parsed)[fnum++].word; alert_vec.push_back(alert); } void kpi_prompt_addsource(KIS_PROMPT_CB_PARMS) { if (ok && globalreg->panel_interface->FetchNetClient() != NULL) { Kis_AddCard_Panel *acp = new Kis_AddCard_Panel(globalreg, globalreg->panel_interface); globalreg->panel_interface->AddPanel(acp); } } void kpi_prompt_warnallerr(KIS_PROMPT_CB_PARMS) { if (check) globalreg->panel_interface->prefs->SetOpt("WARN_ALLERRSOURCE", "false", 1); ((KisPanelInterface *) auxptr)->ResetWarnAllClear(); } void KisPanelInterface::proto_INFO(CLIPROTO_CB_PARMS) { // Numsources,numerrorsources if (proto_parsed->size() < 1) { return; } int fnum = 0; int ns = 0, ne = 0; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &ns) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &ne) != 1) return; if (ns != 0 && ne >= ns) warned_all_errors_consec++; else warned_all_errors_consec = 0; // If we've found all our defined sources, make sure they're not all in // an error state if (ns != 0 && time(0) - warned_all_errors > 60 && warned_cleared && ne >= ns && warned_all_errors_consec > 20 && prefs->FetchOpt("WARN_ALLERRSOURCE") != "false") { warned_all_errors = time(0); warned_all_errors_consec = 0; vector t; t.push_back("All packet sources are in error state."); t.push_back("Kismet will not be able to capture any data"); t.push_back("until a packet source is out of error mode."); t.push_back("In most cases Kismet will continue to try to"); t.push_back("re-enable errored packet sources."); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, this); kpp->SetTitle("Sources Failed"); kpp->SetDisplayText(t); kpp->SetCheckText("Do not show this warning in the future"); kpp->SetChecked(0); kpp->SetDefaultButton(1); kpp->SetButtonText("OK", ""); QueueModalPanel(kpp); } // If we have no sources and we haven't warned the user about that, do so if (ns == 0 && warned_no_sources == 0) { warned_no_sources = 1; vector t; t.push_back("Kismet started with no packet sources defined."); t.push_back("No sources were defined or all defined sources"); t.push_back("encountered unrecoverable errors."); t.push_back("Kismet will not be able to capture any data until"); t.push_back("a capture interface is added. Add a source now?"); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, this); kpp->SetTitle("No sources"); kpp->SetDisplayText(t); kpp->SetCallback(kpi_prompt_addsource, this); kpp->SetButtonText("Yes", "No"); kpp->SetDefaultButton(1); QueueModalPanel(kpp); } } void KisPanelClient_Configured(CLICONF_CB_PARMS) { ((KisPanelInterface *) auxptr)->NetClientConfigure(kcli, recon); } KisPanelInterface::KisPanelInterface() { fprintf(stderr, "FATAL OOPS: KisPanelInterface not called with globalreg\n"); exit(-1); } KisPanelInterface::KisPanelInterface(GlobalRegistry *in_globalreg) : PanelInterface(in_globalreg) { globalreg = in_globalreg; network_client = NULL; prefs = new ConfigFile(globalreg); shutdown_mode = 0; // Load the preferences file LoadPreferences(); // Update the plugin dirs if we didn't get them if (prefs->FetchOptVec("PLUGINDIR").size() == 0) { vector pdv; pdv.push_back("%h/.kismet/client_plugins/"); pdv.push_back(string(LIB_LOC) + "/kismet_client/"); prefs->SetOptVec("PLUGINDIR", pdv, 1); } // Initialize the plugin data record. The first panel to get added // to us is the main panel. plugdata.kpinterface = this; plugdata.mainpanel = NULL; plugdata.globalreg = globalreg; // Fill the plugin paths if they haven't been found ScanPlugins(); addcb_ref = 0; mainp = NULL; server_framework = NULL; server_popen = NULL; server_text_cb = -1; warned_no_sources = 0; warned_all_errors = warned_all_errors_consec = 0; warned_cleared = 1; endwin(); } KisPanelInterface::~KisPanelInterface() { Shutdown(); delete network_client; } void KisPanelInterface::Shutdown() { SavePreferences(); Remove_All_Netcli_Conf_CB(KisPanelClient_Configured); Remove_All_Netcli_ProtoHandler("STATUS", KisPanelClient_STATUS, this); Remove_All_Netcli_ProtoHandler("SOURCE", KisPanelClient_SOURCE, this); Remove_All_Netcli_ProtoHandler("INFO", KisPanelClient_INFO, this); Remove_All_Netcli_ProtoHandler("ALERT", KisPanelClient_ALERT, this); // Destroy panels in this destructor, if they get destroyed in the // parent destructor sadness happens for (unsigned int x = 0; x < live_panels.size(); x++) KillPanel(live_panels[x]); // we don't kill the clients since we might still be issuing shutdown // commands // we don't kill the server if it exists, but we do kill the callback // referencing ourselves if (server_framework != NULL) server_framework->RemoveCallback(server_text_cb); shutdown_mode = 1; } int KisPanelInterface::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { if (shutdown_mode) return in_max_fd; return PanelInterface::MergeSet(in_max_fd, out_rset, out_wset); } int KisPanelInterface::Poll(fd_set& in_rset, fd_set& in_wset) { if (shutdown_mode) return 0; return PanelInterface::Poll(in_rset, in_wset); } void KisPanelInterface::AddPanel(Kis_Panel *in_panel) { in_panel->ShowPanel(); PanelInterface::AddPanel(in_panel); if (plugdata.mainpanel == NULL) plugdata.mainpanel = (Kis_Main_Panel *) in_panel; if (mainp == NULL) mainp = (Kis_Main_Panel *) in_panel; } void KisPanelInterface::KillPanel(Kis_Panel *in_panel) { // Kill the panel (this will delete it so be careful) PanelInterface::KillPanel(in_panel); // If it's a modal panel, remove it from the modal vec list. We only ever display // the head of the modal vec list, so this check is sane. We're also only doing // a pointer compare, so it being destroyed above is also sane if (modal_vec.size() > 0 && modal_vec[0] == in_panel) { modal_vec.erase(modal_vec.begin()); // If we have another modal alert queued, put it up if (modal_vec.size() > 0) AddPanel(modal_vec[0]); } } int KisPanelInterface::LoadPreferences() { if (prefs->ParseConfig(prefs->ExpandLogPath("%h/.kismet/kismet_ui.conf", "", "", 0, 1).c_str()) >= 0) { prefs->SetOpt("LOADEDFROMFILE", "1", 0); } SavePreferences(); return 1; } int KisPanelInterface::SavePreferences() { // Try to make the dir int ret; string dir = prefs->ExpandLogPath("%h/.kismet", "", "", 0, 1); ret = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); if (ret < 0 && errno != EEXIST) { string err = string(strerror(errno)); _MSG("Failed to create dir " + dir + ": " + err, MSGFLAG_ERROR); RaiseAlert("Could not save prefs", "Could not save preferences file, failed to create\n" "directory " + dir + ":\n" " " + err + "\n" "Kismet will continue to run, however changes to\n" "preferences will not be saved.\n"); return -1; } ret = prefs->SaveConfig(prefs->ExpandLogPath("%h/.kismet/kismet_ui.conf", "", "", 0, 1).c_str()); if (ret < 0) RaiseAlert("Could not save prefs", "Could not save the preferences file, check error\n" "messages. Kismet will continue to run, however\n" "preference changes will not be preserved.\n"); return ret; } int KisPanelInterface::AddNetClient(string in_host, int in_reconnect) { if (network_client != NULL) delete network_client; KisNetClient *netcl = new KisNetClient(globalreg); network_client = netcl; netcl->AddConfCallback(KisPanelClient_Configured, 1, this); for (unsigned int x = 0; x < addclicb_vec.size(); x++) (*(addclicb_vec[x]->cb))(globalreg, netcl, 1, addclicb_vec[x]->auxptr); return netcl->Connect(in_host, in_reconnect); } void KisPanelInterface::RemoveNetClient() { if (network_client != NULL) { for (unsigned int c = 0; c < addclicb_vec.size(); c++) (*(addclicb_vec[c]->cb))(globalreg, network_client, 0, addclicb_vec[c]->auxptr); delete network_client; network_client = NULL; } return; } void KisPanelInterface::NetClientConfigure(KisNetClient *in_cli, int in_recon) { // Reset the card list. This assumes we only ever have one client, which // is the case despite the stubs for multi-client. Sorry. We do this here // so we don't get deltas before the reconnect event in configure. for (map::iterator x = netcard_map.begin(); x != netcard_map.end(); ++x) { delete x->second; } netcard_map.clear(); warned_no_sources = 0; warned_all_errors = warned_all_errors_consec = 0; warned_cleared = 1; _MSG("Got configure event for client", MSGFLAG_INFO); if (in_cli->RegisterProtoHandler("STATUS", "text,flags", KisPanelClient_STATUS, this) < 0) { _MSG("Could not register STATUS protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("SOURCE", KPI_SOURCE_FIELDS, KisPanelClient_SOURCE, this) < 0) { _MSG("Could not register SOURCE protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("INFO", "numsources,numerrorsources", KisPanelClient_INFO, this) < 0) { _MSG("Could not register INFO protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } if (in_cli->RegisterProtoHandler("ALERT", KPI_ALERT_FIELDS, KisPanelClient_ALERT, this) < 0) { _MSG("Could not register ALERT protocol with remote server, connection " "will be terminated.", MSGFLAG_ERROR); in_cli->KillConnection(); } } int KisPanelInterface::Remove_All_Netcli_ProtoHandler(string in_proto, CliProto_Callback in_cb, void *in_aux) { if (network_client != NULL) network_client->RemoveProtoHandler(in_proto, in_cb, in_aux); return 0; } void KisPanelInterface::Remove_All_Netcli_Cmd_CB(CliCmd_Callback in_cb, void *in_aux) { if (network_client != NULL) network_client->RemoveAllCmdCallbacks(in_cb, in_aux); return; } void KisPanelInterface::RaiseAlert(string in_title, string in_text) { vector t = StrTokenize(in_text, "\n"); Kis_Prompt_Panel *kpp = new Kis_Prompt_Panel(globalreg, this); kpp->SetTitle(in_title); kpp->SetDisplayText(t); kpp->SetButtonText("OK", ""); if (modal_vec.size() != 0) modal_vec.push_back(kpp); else AddPanel(kpp); } void KisPanelInterface::QueueModalPanel(Kis_Panel *in_panel) { if (modal_vec.size() > 0) { modal_vec.push_back(in_panel); } else { modal_vec.push_back(in_panel); AddPanel(in_panel); } } map *KisPanelInterface::FetchNetCardMap() { return &netcard_map; } int KisPanelInterface::Add_NetCli_AddCli_CB(KPI_AddCli_Callback in_cb, void *in_auxptr) { addcli_cb_rec *cbr = new addcli_cb_rec; cbr->refnum = addcb_ref; cbr->cb = in_cb; cbr->auxptr = in_auxptr; addcb_ref++; addclicb_vec.push_back(cbr); // Call it immediately if we're already connected if (network_client != NULL) { (*(in_cb))(globalreg, network_client, 1, in_auxptr); } return cbr->refnum; } void KisPanelInterface::Remove_Netcli_AddCli_CB(int in_cbref) { for (unsigned int x = 0; x < addclicb_vec.size(); x++) { if (addclicb_vec[x]->refnum == in_cbref) { delete addclicb_vec[x]; addclicb_vec.erase(addclicb_vec.begin() + x); return; } } } void KisPanelInterface::Remove_All_Netcli_Conf_CB(CliConf_Callback in_cb) { if (network_client != NULL) { network_client->RemoveConfCallback(in_cb); } } string global_plugin_load; void PluginClientSignalHandler(int sig) { fprintf(stderr, "\n\n" "FATAL: Kismet (UI) crashed while loading a plugin...\n" "Plugin loading: %s\n\n" "This is either a bug in the plugin, or the plugin needs to be recompiled\n" "to match the version of Kismet you are using (especially if you are using\n" "development versions of Kismet or have recently upgraded.)\n\n" "Remove the plugin from the plugins directory to keep it from loading,\n" "or manually edit ~/.kismet/kismet_ui.conf and remove the plugin_autoload\n" "line to stop Kismet from trying to start it.\n\n", global_plugin_load.c_str()); exit(1); } void KisPanelInterface::LoadPlugin(string in_fname, string in_objname) { void *dlfile; panel_plugin_hook plughook; #ifdef SYS_CYGWIN _sig_func_ptr old_segv = SIG_DFL; #else sig_t old_segv = SIG_DFL; #endif old_segv = signal(SIGSEGV, PluginClientSignalHandler); global_plugin_load = in_fname; if ((dlfile = dlopen(in_fname.c_str(), RTLD_LAZY)) == NULL) { _MSG("Failed to open plugin '" + in_fname + "': " + dlerror(), MSGFLAG_ERROR); signal(SIGSEGV, old_segv); return; } // Resolve the version function panel_plugin_revisioncall vsym = NULL; if ((vsym = (panel_plugin_revisioncall) dlsym(dlfile, "kis_revision_info")) == NULL) { string msg = "Failed to find a Kismet version record in plugin '" + in_fname + "'. This plugin has not been " "updated to use the new version API. Please download the " "latest version, or contact the plugin authors. Kismet will " "still load this plugin, but BE WARNED, there is no way " "to know if it was compiled for this version of Kismet, and " "crashes may occur."; RaiseAlert("Plugin Loading Error", InLineWrap(msg, 0, 50)); } else { // Make a struct of whatever PREV we use, it will tell us what // it supports in response. panel_plugin_revision *prev = new panel_plugin_revision; prev->version_api_revision = KIS_PANEL_PLUGIN_VREVISION; (*vsym)(prev); if (prev->version_api_revision >= 1) { if (prev->major != string(VERSION_MAJOR) || prev->minor != string(VERSION_MINOR) || prev->tiny != string(VERSION_TINY)) { string msg = "Failed to load plugin '" + in_fname + "': This plugin was compiled for a different version of " "Kismet; Please recompile and reinstall it, or remove " "it entirely."; _MSG(msg, MSGFLAG_ERROR); RaiseAlert("Loading Plugin Failed", InLineWrap(msg, 0, 50)); signal(SIGSEGV, old_segv); return; } } delete(prev); } if ((plughook = (panel_plugin_hook) dlsym(dlfile, "panel_plugin_init")) == NULL) { _MSG("Failed to find 'panel_plugin_init' function in plugin '" + in_fname + "': " + strerror(errno), MSGFLAG_ERROR); dlclose(dlfile); signal(SIGSEGV, old_segv); return; } int ret; ret = (*(plughook))(globalreg, &plugdata); if (ret < 0) { _MSG("Failed to initialize plugin '" + in_fname + "'", MSGFLAG_ERROR); dlclose(dlfile); signal(SIGSEGV, old_segv); return; } for (unsigned int x = 0; x < plugin_vec.size(); x++) { if (plugin_vec[x]->filename == in_fname && plugin_vec[x]->objectname == in_objname) { plugin_vec[x]->dlfileptr = dlfile; break; } } signal(SIGSEGV, old_segv); } void KisPanelInterface::ScanPlugins() { vector plugdirs = prefs->FetchOptVec("PLUGINDIR"); for (unsigned int x = 0; x < plugdirs.size(); x++) { DIR *plugdir; struct dirent *plugfile; string expanddir = prefs->ExpandLogPath(plugdirs[x], "", "", 0, 1); if ((plugdir = opendir(expanddir.c_str())) == NULL) { continue; } while ((plugfile = readdir(plugdir)) != NULL) { int loaded = 0; if (plugfile->d_name[0] == '.') continue; string fname = plugfile->d_name; if (fname.find(".so") == fname.length() - 3) { for (unsigned int y = 0; y < plugin_vec.size(); y++) { if (plugin_vec[y]->filename == expanddir + fname) { loaded = 1; break; } } if (loaded) continue; panel_plugin_meta *pm = new panel_plugin_meta; pm->filename = expanddir + fname; pm->objectname = fname; pm->dlfileptr = (void *) 0x0; plugin_vec.push_back(pm); } } closedir(plugdir); } } void KisPanelInterface::LoadPlugins() { // Scan for plugins to auto load vector plugprefs = prefs->FetchOptVec("plugin_autoload"); for (unsigned int x = 0; x < plugin_vec.size(); x++) { for (unsigned int y = 0; y < plugprefs.size(); y++) { if (plugin_vec[x]->objectname == plugprefs[y] && plugin_vec[x]->dlfileptr == 0x0) { _MSG("Auto-loading plugin '" + plugprefs[y] + "'", MSGFLAG_INFO); LoadPlugin(plugin_vec[x]->filename, plugin_vec[x]->objectname); break; } } } } // keep the last 50 lines of server console for when the window is first opened void kpi_textcli_consolevec(TEXTCLI_PARMS) { vector *console = ((KisPanelInterface *) auxptr)->FetchServerConsole(); console->push_back(text); if (console->size() > 100) console->erase(console->begin(), console->begin() + console->size() - 100); } void KisPanelInterface::SpawnServer(string in_parm) { server_parm = in_parm; SpawnServer(); } void kpi_serverpopen_fail(CLIFRAME_FAIL_CB_PARMS) { ((KisPanelInterface *) auxptr)->RaiseAlert("Kismet Server Failed", InLineWrap("Locally started Kismet server exited unexpectedly " "with error " + IntToString(in_errno) + ". Something " "has gone wrong. Check the Kismet server console for " "more information and errors.", 0, 50)); } void KisPanelInterface::SpawnServer() { string servercmd = string(BIN_LOC) + "/kismet_server " + server_parm; if (server_framework == NULL) { server_framework = new TextCliFrame(globalreg); server_popen = new PopenClient(globalreg); server_framework->RegisterNetworkClient(server_popen); server_framework->RegisterFailCB(kpi_serverpopen_fail, this); server_popen->RegisterClientFramework(server_framework); server_text_cb = server_framework->RegisterCallback(kpi_textcli_consolevec, this); if (server_popen->Connect(servercmd.c_str(), 'r', NULL, NULL) < 0) { _MSG("Failed to launch kismet_server", MSGFLAG_ERROR); delete server_popen; delete server_framework; server_popen = NULL; server_framework = NULL; } } } void KisPanelInterface::KillServer() { if (server_framework != NULL) { server_popen->SoftKillConnection(); server_framework->RemoveCallback(server_text_cb); } } #endif kismet-2013-03-R1b/config.h.bot0000664000175000017500000000175312124602454015662 0ustar dragorndragorn/* proftpd argv stuff */ #define PF_ARGV_NONE 0 #define PF_ARGV_NEW 1 #define PF_ARGV_WRITEABLE 2 #define PF_ARGV_PSTAT 3 #define PF_ARGV_PSSTRINGS 4 /* Maximum number of characters in the status line */ #define STATUS_MAX 1024 /* Maximum number of channels - I've only ever heard of 14 being used. */ #define CHANNEL_MAX 14 /* Stupid ncurses */ #define NCURSES_NOMACROS /* Number of hex pairs in a key */ #define WEPKEY_MAX 32 /* String length of a key */ #define WEPKEYSTR_MAX ((WEPKEY_MAX * 2) + WEPKEY_MAX) /* Number of past alerts to queue for new clients */ #define ALERT_BACKLOG 50 /* system min isn't reliable */ #define kismin(x,y) ((x) < (y) ? (x) : (y)) #define kismax(x,y) ((x) > (y) ? (x) : (y)) // Timer slices per second #define SERVER_TIMESLICES_SEC 10 // Max chars in SSID #define MAX_SSID_LEN 255 /* Namespace (on non-obj-c files) */ #ifndef __IN_OBJC_FILE__ using namespace std; #define __STL_USE_NAMESPACES #endif #ifndef _ #define _(x) x #endif kismet-2013-03-R1b/gpswrapper.cc0000664000175000017500000001216412124602454016160 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "getopt.h" #include "gpscore.h" #include "gpsserial.h" #include "gpsdclient.h" #include "gpsfixed.h" #include "gpswrapper.h" #include "configfile.h" void GpsWrapper::Usage(char *name) { printf(" *** Kismet GPS Options ***\n"); printf(" --use-gpsd-gps (h:p) Use GPSD-controlled GPS at host:port\n" " (default: localhost:2947)\n" " --use-nmea-gps (dev) Use local NMEA serial GPS on device\n" " (default: /dev/ttyUSB0)\n" " --use-virtual-gps\n" " (lat,lon,alt) Use a virtual fixed-position gps record\n" " --gps-modelock Force broken GPS units to act as if they\n" " have a valid signal (true/false)\n" " --gps-reconnect Reconnect if a GPS device fails\n" " (true/false)\n"); } GpsWrapper::GpsWrapper(GlobalRegistry *globalreg) { string gpsopt = ""; string gpsparm = ""; int gpsdc = globalreg->getopt_long_num++; int nmeac = globalreg->getopt_long_num++; int modec = globalreg->getopt_long_num++; int recoc = globalreg->getopt_long_num++; int fixec = globalreg->getopt_long_num++; if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: GpsWrapper() called before kismet_config\n"); exit(1); } static struct option gpswrapper_long_options[] = { { "use-gpsd-gps", optional_argument, 0, gpsdc }, { "use-nmea-gps", optional_argument, 0, nmeac }, { "use-virtual-gps", required_argument, 0, fixec }, { "gps-modelock", required_argument, 0, modec }, { "gps-reconnect", required_argument, 0, recoc }, { 0, 0, 0, 0 } }; int option_idx = 0; optind = 0; gps = NULL; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-", gpswrapper_long_options, &option_idx); if (r < 0) break; if (r == gpsdc) { if (optarg != NULL) gpsparm = string(optarg); else gpsparm = "localhost:2947"; _MSG("Using GPSD connected GPS at " + gpsparm, MSGFLAG_INFO); globalreg->kismet_config->SetOpt("gps", "true", 1); globalreg->kismet_config->SetOpt("gpstype", "gpsd", 1); globalreg->kismet_config->SetOpt("gpshost", gpsparm, 1); } if (r == nmeac) { if (optarg != NULL) gpsparm = string(optarg); else gpsparm = "/dev/ttyUSB0"; _MSG("Using NMEA serial connected GPS at " + gpsparm, MSGFLAG_INFO); globalreg->kismet_config->SetOpt("gps", "true", 1); globalreg->kismet_config->SetOpt("gpstype", "serial", 1); globalreg->kismet_config->SetOpt("gpsdevice", gpsparm, 1); } if (r == fixec) { float tlat, tlon, talt; int fnum; if ((fnum = sscanf(optarg, "%f,%f,%f", &tlat, &tlon, &talt)) < 2) { _MSG("Invalid use-virtual-gps, expected lat,lon,alt", MSGFLAG_ERROR); globalreg->kismet_config->SetOpt("gpsposition", "", 1); } else { globalreg->kismet_config->SetOpt("gps", "true", 1); globalreg->kismet_config->SetOpt("gpstype", "virtual", 1); globalreg->kismet_config->SetOpt("gpsposition", FloatToString(tlat) + "," + FloatToString(tlon), 1); if (fnum > 2) globalreg->kismet_config->SetOpt("gpsaltitude", FloatToString(talt), 1); else globalreg->kismet_config->SetOpt("gpsaltitude", "", 1); } } if (r == modec) { globalreg->kismet_config->SetOpt("gpsmodelock", optarg, 1); } if (r == recoc) { globalreg->kismet_config->SetOpt("gpsreconnect", optarg, 1); } } // if (globalreg->kismet_config->FetchOpt("gps") != "true") { if (globalreg->kismet_config->FetchOptBoolean("gps", 0) != 1) { _MSG("GPS support disabled in kismet.conf", MSGFLAG_INFO); GPSNull *gn; gn = new GPSNull(globalreg); return; } gpsopt = globalreg->kismet_config->FetchOpt("gpstype"); if (gpsopt == "serial") { GPSSerial *gs; gs = new GPSSerial(globalreg); gps = gs; } else if (gpsopt == "gpsd") { GPSDClient *gc; gc = new GPSDClient(globalreg); gps = gc; } else if (gpsopt == "virtual") { GPSFixed *gf = new GPSFixed(globalreg); gps = gf; } else if (gpsopt == "") { _MSG("GPS enabled but gpstype missing from kismet.conf", MSGFLAG_FATAL); globalreg->fatal_condition = 1; } else { _MSG("GPS unknown gpstype " + gpsopt + ", continuing on blindly and hoping " "we get something useful. Unless you have loaded GPS plugins that " "handle this GPS type, Kismet is not going to be able to use the GPS", MSGFLAG_ERROR); } } kismet-2013-03-R1b/dumpfile_string.cc0000664000175000017500000000725512124602454017166 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "dumpfile_string.h" int dumpfilestring_chain_hook(CHAINCALL_PARMS) { Dumpfile_String *auxptr = (Dumpfile_String *) auxdata; return auxptr->chain_handler(in_pack); } Dumpfile_String::Dumpfile_String() { fprintf(stderr, "FATAL OOPS: Dumpfile_String called with no globalreg\n"); exit(1); } Dumpfile_String::Dumpfile_String(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { char errstr[STATUS_MAX]; globalreg = in_globalreg; stringfile = NULL; type = "string"; if (globalreg->sourcetracker == NULL) { fprintf(stderr, "FATAL OOPS: Sourcetracker missing before " "Dumpfile_String\n"); exit(1); } if (globalreg->builtindissector == NULL) { fprintf(stderr, "FATAL OOPS: Sourcetracker missing before " "Dumpfile_String\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("string")) == "" || globalreg->fatal_condition) { return; } stringfile = fopen(fname.c_str(), "w"); if (stringfile == NULL) { snprintf(errstr, STATUS_MAX, "Failed to open string dump file '%s': %s", fname.c_str(), strerror(errno)); _MSG(errstr, MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } _MSG("Opened string log file '" + fname + "'", MSGFLAG_INFO); globalreg->packetchain->RegisterHandler(&dumpfilestring_chain_hook, this, CHAINPOS_LOGGING, -100); globalreg->RegisterDumpFile(this); globalreg->builtindissector->SetStringExtract(2); _MSG("Dumpfile_String - forced string extraction from packets at all times", MSGFLAG_INFO); } Dumpfile_String::~Dumpfile_String() { globalreg->packetchain->RemoveHandler(&dumpfilestring_chain_hook, CHAINPOS_LOGGING); // Close files if (stringfile != NULL) { Flush(); fclose(stringfile); } stringfile = NULL; } int Dumpfile_String::Flush() { if (stringfile == NULL) return 0; fflush(stringfile); return 1; } int Dumpfile_String::chain_handler(kis_packet *in_pack) { if (stringfile == NULL) return 0; kis_string_info *stringinfo = NULL; if (in_pack->error) return 0; // Grab the 80211 info, compare, bail kis_ieee80211_packinfo *packinfo; if ((packinfo = (kis_ieee80211_packinfo *) in_pack->fetch(_PCM(PACK_COMP_80211))) == NULL) return 0; if (packinfo->corrupt) return 0; if (packinfo->type != packet_data || packinfo->subtype != packet_sub_data) return 0; // If it's encrypted and hasn't been decrypted, we can't do anything // smart with it, so toss. if (packinfo->cryptset != 0 && packinfo->decrypted == 0) return 0; // Grab the strings stringinfo = (kis_string_info *) in_pack->fetch(_PCM(PACK_COMP_STRINGS)); if (stringinfo == NULL) return 0; for (unsigned int x = 0; x < stringinfo->extracted_strings.size(); x++) { fprintf(stringfile, "%s %s %s %s\n", packinfo->bssid_mac.Mac2String().c_str(), packinfo->source_mac.Mac2String().c_str(), packinfo->dest_mac.Mac2String().c_str(), stringinfo->extracted_strings[x].c_str()); } dumped_frames++; return 1; } kismet-2013-03-R1b/dumpfile.cc0000664000175000017500000001030512124602454015566 0ustar dragorndragorn/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "dumpfile.h" #include "getopt.h" Dumpfile::Dumpfile() { fprintf(stderr, "FATAL OOPS: Dumpfile() called with no global registry\n"); exit(1); } Dumpfile::Dumpfile(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; resume = 0; dumped_frames = 0; log_volatile = 0; if (globalreg->kismet_config != NULL) { export_filter = new FilterCore(globalreg); vector filterlines = globalreg->kismet_config->FetchOptVec("filter_export"); for (unsigned int fl = 0; fl < filterlines.size(); fl++) { if (export_filter->AddFilterLine(filterlines[fl]) < 0) { _MSG("Failed to add filter_export config line from the Kismet config " "file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } } } } Dumpfile::~Dumpfile() { if (fname != "") { if (log_volatile && dumped_frames == 0) { _MSG("Closed " + type + " log file '" + fname + "', no packets logged, " "removing empty file.", MSGFLAG_INFO); unlink(fname.c_str()); } else { _MSG("Closed " + type + " log file '" + fname + "', " + IntToString(dumped_frames) + " logged.", MSGFLAG_INFO); } } } void Dumpfile::Usage(char *name) { printf(" *** Dump/Logging Options ***\n"); printf(" -T, --log-types Override activated log types\n" " -t, --log-title Override default log title\n" " -p, --log-prefix <prefix> Directory to store log files\n" " -n, --no-logging Disable logging entirely\n"); } string Dumpfile::ProcessConfigOpt(string in_type) { string logtypes, logtemplate, logname; int option_idx = 0; string retfname; // longopts for the packetsourcetracker component static struct option logfile_long_options[] = { { "log-types", required_argument, 0, 'T' }, { "log-title", required_argument, 0, 't' }, { "log-prefix", required_argument, 0, 'p' }, { "no-logging", no_argument, 0, 'n' }, { 0, 0, 0, 0 } }; if ((logtemplate = globalreg->kismet_config->FetchOpt("logtemplate")) == "") { _MSG("No 'logtemplate' specified in the Kismet config file.", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return ""; } // Hack the extern getopt index optind = 0; while (1) { int r = getopt_long(globalreg->argc, globalreg->argv, "-T:t:np:", logfile_long_options, &option_idx); if (r < 0) break; switch (r) { case 'T': logtypes = string(optarg); break; case 't': logname = string(optarg); break; case 'n': return ""; break; case 'p': globalreg->log_prefix = string(optarg); break; } } if (logname.length() == 0 && (logname = globalreg->kismet_config->FetchOpt("logdefault")) == "") { _MSG("No 'logdefault' specified on the command line or config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return ""; } if (logtypes.length() == 0 && (logtypes = globalreg->kismet_config->FetchOpt("logtypes")) == "") { _MSG("No 'logtypes' specified on the command line or config file", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return ""; } vector<string> typevec = StrTokenize(StrLower(logtypes), ","); in_type = StrLower(in_type); // lower local copy int factive = 0; for (unsigned int x = 0; x < typevec.size(); x++) { if (typevec[x] == in_type) { factive = 1; break; } } if (factive == 0) { return ""; } // _MSG("Log file type '" + in_type + "' activated.", MSGFLAG_INFO); retfname = globalreg->kismet_config->ExpandLogPath(logtemplate, logname, in_type, 0, 0); return retfname; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/gpsdclient.cc��������������������������������������������������������������������0000664�0001750�0001750�00000042265�12124602454�016127� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef HAVE_LIBGPS #include "gpsdclient.h" #include "configfile.h" #include "soundcontrol.h" #include "packetchain.h" #include "kismet_json.h" int GpsdGpsEvent(Timetracker::timer_event *evt, void *parm, GlobalRegistry *globalreg) { GPSDClient *gps = (GPSDClient *) parm; return gps->Timer(); } GPSDClient::GPSDClient() { fprintf(stderr, "FATAL OOPS: gpsdclient called with no globalreg\n"); exit(-1); } void gpsdc_connect_hook(GlobalRegistry *globalreg, int status, void *auxptr) { ((GPSDClient *) auxptr)->ConnectCB(status); } void GPSDClient::ConnectCB(int status) { ostringstream osstr; if (status != 0) { if (reconnect_attempt < 0) { globalreg->messagebus->InjectMessage("Could not connect to GPSD server", MSGFLAG_ERROR); globalreg->messagebus->InjectMessage("GPSD reconnection not enabled, " "disabling GPSD", MSGFLAG_ERROR); return; } /* snprintf(errstr, STATUS_MAX, "Could not connect to the GPSD server, will " "reconnect in %d seconds", kismin(reconnect_attempt + 1, 6) * 5); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); */ reconnect_attempt++; last_disconnect = globalreg->timestamp.tv_sec; return; } // Set the poll mode to initial setup and call the timer poll_mode = -1; last_hed_time = 0; si_units = 0; reconnect_attempt = 1; last_disconnect = 0; gps_connected = 0; return; } GPSDClient::GPSDClient(GlobalRegistry *in_globalreg) : GPSCore(in_globalreg) { // The only GPSD connection method we support is a plain // old TCP connection so we can generate it all internally tcpcli = new TcpClient(globalreg); netclient = tcpcli; // Attach it to ourselves and opposite RegisterNetworkClient(tcpcli); tcpcli->RegisterClientFramework(this); gpseventid = -1; poll_mode = -1; last_hed_time = 0; si_units = 0; ScanOptions(); RegisterComponents(); gpseventid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &GpsdGpsEvent, (void *) this); char temphost[129]; if (sscanf(globalreg->kismet_config->FetchOpt("gpshost").c_str(), "%128[^:]:%d", temphost, &port) != 2) { globalreg->messagebus->InjectMessage("Invalid GPS host in config, " "host:port required", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } snprintf(host, MAXHOSTNAMELEN, "%s", temphost); last_mode = -1; last_tpv = last_update = globalreg->timestamp.tv_sec; snprintf(errstr, STATUS_MAX, "Using GPSD server on %s:%d", host, port); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_INFO); tcpcli->Connect(host, port, gpsdc_connect_hook, this); } GPSDClient::~GPSDClient() { // Unregister ourselves from the main tcp service loop globalreg->RemovePollableSubsys(this); KillConnection(); } int GPSDClient::Shutdown() { if (tcpcli != NULL) { tcpcli->FlushRings(); tcpcli->KillConnection(); } return 1; } int GPSDClient::Timer() { int ret = 0; // Timed backoff up to 30 seconds if (netclient->Valid() == 0 && reconnect_attempt >= 0 && (globalreg->timestamp.tv_sec - last_disconnect >= (kismin(reconnect_attempt, 6) * 5))) { Reconnect(); } // Send version probe if we're setting up a new connection // Send the poll command if we're stuck in older polling mode if (netclient->Valid()) { if (globalreg->timestamp.tv_sec - last_tpv > 3) { // Assume we lost link, gpsd doens't properly tell us mode = 0; } if (globalreg->timestamp.tv_sec - last_update > 15) { _MSG("No update from GPSD in 15 seconds or more, attempting to " "reconnect", MSGFLAG_ERROR); mode = 0; netclient->KillConnection(); last_update = last_disconnect = globalreg->timestamp.tv_sec; GPSCore::Timer(); return 1; } if (poll_mode < 0) { ret = netclient->WriteData((void *) gpsd_init_command, strlen(gpsd_init_command)); poll_mode = 0; netclient->FlushRings(); } else if (poll_mode == 1) { ret = netclient->WriteData((void *) gpsd_poll_command, strlen(gpsd_poll_command)); netclient->FlushRings(); } if (ret < 0 || globalreg->fatal_condition) { last_disconnect = globalreg->timestamp.tv_sec; return -1; } } GPSCore::Timer(); return 1; } int GPSDClient::Reconnect() { tcpcli->Connect(host, port, gpsdc_connect_hook, this); return 1; } int GPSDClient::ParseData() { int len, rlen, roft = 0; char *buf; string strbuf; float in_lat = 0, in_lon = 0, in_alt = 0, in_spd = 0, in_hed = 0, in_hdop = 0, in_vdop = 0; int in_mode, use_alt = 1, use_spd = 1, use_hed = 1, use_data = 0, use_mode = 0, use_coord = 0, use_dop = 0;; len = netclient->FetchReadLen(); buf = new char[len + 1]; if (netclient->ReadData(buf, len, &rlen) < 0) { globalreg->messagebus->InjectMessage("GPSDClient::ParseData failed to " "fetch data from the tcp connection.", MSGFLAG_ERROR); return -1; } if (rlen <= 0) { return 0; } buf[rlen] = '\0'; for (roft = 0; roft < rlen; roft++) { if (buf[roft] != 0) { break; } } // Parse without including partials, so we don't get a fragmented command // out of the buffer vector<string> inptok = StrTokenize(buf + roft, "\n", 0); delete[] buf; // Bail on no useful data if (inptok.size() <= 0) { return 0; } for (unsigned int it = 0; it < inptok.size(); it++) { // No matter what we've dealt with this data block netclient->MarkRead(inptok[it].length() + 1 + roft); // Trim garbage out of it inptok[it] = StrPrintable(inptok[it]); last_update = globalreg->timestamp.tv_sec; // Do we look like JSON? If it is, we process it independently of the normal // methods... if (inptok[it][0] == '{') { struct JSON_value *json; string err; json = JSON_parse(inptok[it], err); if (err.length() != 0) { _MSG("Invalid JSON data block from GPSD: " + err, MSGFLAG_ERROR); continue; } // printf("debug - GPS JSON:\n"); // JSON_dump(json, "", 0); string msg_class = JSON_dict_get_string(json, "class", err); if (msg_class == "VERSION") { _MSG("Connected to a JSON-enabled GPSD version " + MungeToPrintable(JSON_dict_get_string(json, "release", err)) + ", turning on JSON mode", MSGFLAG_INFO); // Set JSON mode poll_mode = 10; // We get speed in meters/sec si_units = 1; if (netclient->WriteData((void *) "?WATCH={\"json\":true};\n", 22) < 0 || globalreg->fatal_condition) { last_disconnect = globalreg->timestamp.tv_sec; return 0; } } else if (msg_class == "TPV") { float n; last_tpv = globalreg->timestamp.tv_sec; gps_connected = 1; n = JSON_dict_get_number(json, "mode", err); if (err.length() == 0) { in_mode = (int) n; use_mode = 1; } // If we have a valid alt, use it if (in_mode > 2) { n = JSON_dict_get_number(json, "alt", err); if (err.length() == 0) { in_alt = n; use_alt = 1; } } if (in_mode >= 2) { // If we have LAT and LON, use them n = JSON_dict_get_number(json, "lat", err); if (err.length() == 0) { in_lat = n; n = JSON_dict_get_number(json, "lon", err); if (err.length() == 0) { in_lon = n; use_coord = 1; use_data = 1; } } // If we have HDOP and VDOP, use them n = JSON_dict_get_number(json, "epx", err); if (err.length() == 0) { in_hdop = n; n = JSON_dict_get_number(json, "epy", err); if (err.length() == 0) { in_vdop = n; use_dop = 1; } } // Heading (track in gpsd speak) n = JSON_dict_get_number(json, "track", err); if (err.length() == 0) { in_hed = n; use_hed = 1; } // Speed n = JSON_dict_get_number(json, "speed", err); if (err.length() == 0) { in_spd = n; use_spd = 1; } } } else if (msg_class == "SKY") { GPSCore::sat_pos sp; struct JSON_value *v = NULL, *s = NULL; gps_connected = 1; v = JSON_dict_get_value(json, "satellites", err); if (err.length() == 0 && v != NULL) { sat_pos_map.clear(); if (v->value.tok_type == JSON_arrstart) { for (unsigned int z = 0; z < v->value_array.size(); z++) { float prn = 0, ele = 0, az = 0, snr = 0; int valid = 1; s = v->value_array[z]; // If we're not a dictionary in the sat array, skip if (s->value.tok_type != JSON_start) { continue; } prn = JSON_dict_get_number(s, "PRN", err); if (err.length() != 0) valid = 0; ele = JSON_dict_get_number(s, "el", err); if (err.length() != 0) valid = 0; az = JSON_dict_get_number(s, "az", err); if (err.length() != 0) valid = 0; snr = JSON_dict_get_number(s, "ss", err); if (err.length() != 0) valid = 0; if (valid) { sp.prn = prn; sp.elevation = ele; sp.azimuth = az; sp.snr = snr; sat_pos_map[prn] = sp; } } } } } JSON_delete(json); } else if (poll_mode == 0 && inptok[it] == "GPSD") { // Look for a really old gpsd which doesn't do anything intelligent // with the L (version) command. Only do this once, if we've already // figured out a poll mode then there's not much point in hammering // the server. Force us into watch mode. poll_mode = 1; Timer(); continue; } else if (poll_mode < 10 && inptok[it].substr(0, 15) == "GPSD,L=2 1.0-25") { // Maemo ships a broken,broken GPS which doesn't parse NMEA correctly // and results in no alt or fix in watcher or polling modes, so we // have to detect this version and kick it into debug R=1 mode // and do NMEA ourselves. if (netclient->WriteData((void *) "R=1\n", 4) < 0 || globalreg->fatal_condition) { last_disconnect = globalreg->timestamp.tv_sec; return 0; } // Use raw for position si_raw = 1; } else if (poll_mode < 10 && inptok[it].substr(0, 7) == "GPSD,L=") { // Look for the version response vector<string> lvec = StrTokenize(inptok[it], " "); int gma, gmi; gps_connected = 1; if (lvec.size() < 3) { poll_mode = 1; } else if (sscanf(lvec[1].c_str(), "%d.%d", &gma, &gmi) != 2) { poll_mode = 1; } else { if (gma < 2 || (gma == 2 && gmi < 34)) { poll_mode = 1; } // Since GPSD r2368 'O' gives the speed as m/s instead of knots if (gma > 2 || (gma == 2 && gmi >= 31)) { si_units = 1; } } // Don't use raw for position si_raw = 0; // If we're still in poll mode 0, write the watcher command. // This has been merged into one command because gpsd apparently // silently drops the second command sent too quickly if (netclient->WriteData((void *) gpsd_watch_command, strlen(gpsd_watch_command)) < 0 || globalreg->fatal_condition) { last_disconnect = globalreg->timestamp.tv_sec; return 0; } } else if (poll_mode < 10 && inptok[it].substr(0, 7) == "GPSD,P=") { gps_connected = 1; // Poll lines vector<string> pollvec = StrTokenize(inptok[it], ","); if (pollvec.size() < 5) { continue; } if (sscanf(pollvec[1].c_str(), "P=%f %f", &in_lat, &in_lon) != 2) { continue; } if (sscanf(pollvec[4].c_str(), "M=%d", &in_mode) != 1) { continue; } if (sscanf(pollvec[2].c_str(), "A=%f", &in_alt) != 1) use_alt = 0; if (sscanf(pollvec[3].c_str(), "V=%f", &in_spd) != 1) use_spd = 0; use_hed = 0; use_mode = 1; use_coord = 1; use_data = 1; } else if (poll_mode < 10 && inptok[it].substr(0, 7) == "GPSD,O=") { gps_connected = 1; // Look for O= watch lines vector<string> ggavec = StrTokenize(inptok[it], " "); if (ggavec.size() < 15) { continue; } // Total fail if we can't get lat/lon/mode if (sscanf(ggavec[3].c_str(), "%f", &in_lat) != 1) continue; if (sscanf(ggavec[4].c_str(), "%f", &in_lon) != 1) continue; if (sscanf(ggavec[14].c_str(), "%d", &in_mode) != 1) continue; if (sscanf(ggavec[5].c_str(), "%f", &in_alt) != 1) use_alt = 0; if (sscanf(ggavec[6].c_str(), "%f", &in_hdop) != 1) use_dop = 0; if (sscanf(ggavec[7].c_str(), "%f", &in_vdop) != 1) use_dop = 0; if (sscanf(ggavec[8].c_str(), "%f", &in_hed) != 1) use_hed = 0; if (sscanf(ggavec[9].c_str(), "%f", &in_spd) != 1) use_spd = 0; #if 0 if (si_units == 0) in_spd *= 0.514; /* Speed in meters/sec from knots */ #endif use_mode = 1; use_coord = 1; use_data = 1; } else if (poll_mode < 10 && si_raw && inptok[it].substr(0, 6) == "$GPGSA") { gps_connected = 1; vector<string> savec = StrTokenize(inptok[it], ","); if (savec.size() != 18) continue; if (sscanf(savec[2].c_str(), "%d", &in_mode) != 1) continue; use_mode = 1; use_data = 1; /* } else if (si_raw && inptok[it].substr(0, 6) == "$GPVTG") { vector<string> vtvec = StrTokenize(inptok[it], ","); if (vtvec.size() != 10) continue; if (sscanf(vtvec[7].c_str(), "%f", &in_spd) != 1) continue; use_spd = 1; use_data = 1; */ } else if (poll_mode < 10 && si_raw && inptok[it].substr(0, 6) == "$GPGGA") { gps_connected = 1; vector<string> gavec = StrTokenize(inptok[it], ","); int tint; float tfloat; if (gavec.size() != 15) continue; if (sscanf(gavec[2].c_str(), "%2d%f", &tint, &tfloat) != 2) continue; in_lat = (float) tint + (tfloat / 60); if (gavec[3] == "S") in_lat = in_lat * -1; if (sscanf(gavec[4].c_str(), "%3d%f", &tint, &tfloat) != 2) continue; in_lon = (float) tint + (tfloat / 60); if (gavec[5] == "W") in_lon = in_lon * -1; if (sscanf(gavec[9].c_str(), "%f", &tfloat) != 1) continue; in_alt = tfloat; use_coord = 1; use_alt = 1; use_data = 1; } else if (poll_mode < 10 && inptok[it].substr(0, 6) == "$GPGSV") { // $GPGSV,3,1,09,22,80,170,40,14,58,305,19,01,46,291,,18,44,140,33*7B // $GPGSV,3,2,09,05,39,105,31,12,34,088,32,30,31,137,31,09,26,047,34*72 // $GPGSV,3,3,09,31,26,222,31*46 // // # of sentences for data // sentence # // # of sats in view // // sat # // elevation // azimuth // snr gps_connected = 1; vector<string> svvec = StrTokenize(inptok[it], ","); GPSCore::sat_pos sp; if (svvec.size() < 6) continue; // If we're on the last sentence, move the new vec to the transmitted one if (svvec[1] == svvec[2]) { sat_pos_map = sat_pos_map_tmp; sat_pos_map_tmp.clear(); } unsigned int pos = 4; while (pos + 4 < svvec.size()) { if (sscanf(svvec[pos++].c_str(), "%d", &sp.prn) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.elevation) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.azimuth) != 1) break; if (sscanf(svvec[pos++].c_str(), "%d", &sp.snr) != 1) sp.snr = 0; sat_pos_map_tmp[sp.prn] = sp; } continue; } } if (in_alt == 0 && in_lat == 0 && in_lon == 0) use_data = 0; if (use_data == 0) return 1; if ((gps_options & GPSD_OPT_FORCEMODE) && in_mode < 2) { in_mode = 2; } else if (in_mode < 2) { in_mode = 0; } if (use_dop) { hdop = in_hdop; vdop = in_vdop; } // Some internal mode jitter protection, means our mode is slightly lagged if (use_mode) { if (in_mode >= last_mode) { last_mode = in_mode; mode = in_mode; } else { last_mode = in_mode; } } // Return metric for now if (use_alt) alt = in_alt; // * 3.3; // If we're using speed,and if we're in the older gpsd that provides it in // knots, convert it, otherwise it's already meters/sec if (use_spd) { if (si_units == 0) in_spd *= 0.514; /* Speed in meters/sec from knots */ spd = in_spd; } if (use_hed) { last_hed = hed; hed = in_hed; } else if (poll_mode && use_coord) { // We only do manual heading calcs in poll mode if (last_hed_time == 0) { last_hed_time = globalreg->timestamp.tv_sec; } else if (globalreg->timestamp.tv_sec - last_hed_time > 1) { // It's been more than a second since we updated the heading, so we // can back up the lat/lon and do hed calcs last_lat = lat; last_lon = lon; last_hed = hed; hed = CalcHeading(in_lat, in_lon, last_lat, last_lon); last_hed_time = globalreg->timestamp.tv_sec; } } // We always get these... But we get them at the end so that we can // preserve our heading calculations if (use_coord) { lat = in_lat; lon = in_lon; // Update the "did we ever get anything" so we say "no fix" not "no gps" // as soon as we get a valid sentence of any sort gps_ever_lock = 1; } return 1; } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/soundcontrol.cc������������������������������������������������������������������0000664�0001750�0001750�00000021172�12124602454�016516� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <sstream> #include "soundcontrol.h" #include "messagebus.h" #include "configfile.h" char speech_alphabet[2][36][12]={ {"owl pha", "Bravo", "Charlie", "Deltah", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", "Keylo", "line-ah", "Mike", "November", "Oscar", "Pawpa", "qwa-bec", "Romeo", "Sierra", "Tango", "you-niform", "vickk-tour", "Whiskey", "ecks-ray", "Yankee", "Zulu", "0", "1", "2", "3", "4", "5", "6", "7", "8", "niner"}, {"ae", "BEE", "SEE", "DEE", "EAE", "EF", "GEE", "H", "EYE", "JAY", "KAY", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} }; int sound_ipc_callback(IPC_CMD_PARMS) { soundcontrol_ipc_frame *f; if (parent) return 0; if (len < (int) sizeof(soundcontrol_ipc_frame)) { _MSG("IPC sound handler got a short sound message", MSGFLAG_ERROR); return 0; } f = (soundcontrol_ipc_frame *) data; // Don't play events that are too old if (time(0) - f->timestamp > 2) return 0; int ret = ((SoundControl *) auxptr)->LocalPlay(f->player, f->msg); if (ret < 0) return -1; return 0; } int speech_ipc_callback(IPC_CMD_PARMS) { soundcontrol_ipc_frame *f; if (parent) return 0; if (len < (int) sizeof(soundcontrol_ipc_frame)) { _MSG("IPC sound handler got a short sound message", MSGFLAG_ERROR); return 0; } f = (soundcontrol_ipc_frame *) data; // Don't play events that are too old if (time(0) - f->timestamp > 2) return 0; int ret = ((SoundControl *) auxptr)->LocalSpeech(f->player, f->opt, f->msg); if (ret < 0) return -1; return 0; } SoundControl::SoundControl() { fprintf(stderr, "*** SoundControl() called with no global registry\n"); globalreg = NULL; } SoundControl::SoundControl(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; sound_enable = 0; speech_enable = 0; speech_festival = 0; if ((nulfd = open("/dev/null", O_RDWR)) < 0) { _MSG("SoundControl() opening /dev/null failed (" + string(strerror(errno)) + ") something is weird with your system.)", MSGFLAG_ERROR); } // Always spawn the sound control daemon sound_remote = new IPCRemote(globalreg, "sound daemon"); sound_ipc_id = sound_remote->RegisterIPCCmd(&sound_ipc_callback, NULL, this, "SOUND"); speech_ipc_id = sound_remote->RegisterIPCCmd(&speech_ipc_callback, NULL, this, "SPEECH"); shutdown = 0; } SoundControl::~SoundControl() { Shutdown(); } void SoundControl::SetSpeechEncode(string in_encode) { string lenc = StrLower(in_encode); if (lenc == "nato") speech_encoding = SPEECH_ENCODING_NATO; else if (lenc == "spell") speech_encoding = SPEECH_ENCODING_SPELL; else speech_encoding = SPEECH_ENCODING_NORMAL; } int SoundControl::PlaySound(string in_text) { // fprintf(stderr, "debug - playsound %s enable %d\n", in_text.c_str(), sound_enable); if (sound_enable <= 0) return 0; return SendPacket(in_text, player, 0, sound_ipc_id); } int SoundControl::SayText(string in_text) { if (speech_enable <= 0) return 0; return SendPacket(in_text, speaker, speech_festival, speech_ipc_id); } int SoundControl::SendPacket(string text, string in_player, int opt, int id) { if (shutdown) return 0; // fprintf(stderr, "debug - fetchpid %d\n", sound_remote->FetchSpawnPid()); if (sound_remote->FetchSpawnPid() <= 0) { if (SpawnChildProcess() < 0 || globalreg->fatal_condition) return -1; } ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(soundcontrol_ipc_frame) + text.length() + 1); soundcontrol_ipc_frame *frame = (soundcontrol_ipc_frame *) pack->data; snprintf(frame->player, 256, "%s", in_player.c_str()); snprintf(frame->msg, text.length() + 1, "%s", text.c_str()); frame->opt = opt; frame->timestamp = time(0); pack->data_len = sizeof(soundcontrol_ipc_frame) + text.length() + 1; pack->ipc_cmdnum = id; pack->ipc_ack = 0; sound_remote->SendIPC(pack); return 1; } void SoundControl::Shutdown() { if (sound_remote) { sound_remote->ShutdownIPC(NULL); globalreg->RemovePollableSubsys(sound_remote); delete sound_remote; } sound_remote = NULL; shutdown = 1; } int SoundControl::SpawnChildProcess() { ostringstream osstr; // fprintf(stderr, "debug - soundremote spawnipc\n"); int ret = sound_remote->SpawnIPC(); if (ret < 0 || globalreg->fatal_condition) { _MSG("SoundControl failed to create an IPC child process", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } osstr << "SoundControl spawned IPC child process pid " << sound_remote->FetchSpawnPid(); _MSG(osstr.str(), MSGFLAG_INFO); // fprintf(stderr, "debug - soundremote syncipc\n"); sound_remote->SyncIPC(); return 1; } string SoundControl::EncodeSpeechString(string in_str) { if (speech_encoding != SPEECH_ENCODING_NATO && speech_encoding != SPEECH_ENCODING_SPELL) return in_str; string encodestr; for (unsigned int x = 0; x < in_str.length(); x++) { char chr = toupper(in_str[x]); int pos; // Find our encoding in the array if (chr >= '0' && chr <= '9') pos = 26 + (chr - '0'); else if (chr >= 'A' && chr <= 'Z') pos = chr - 'A'; else continue; if (speech_encoding == SPEECH_ENCODING_NATO) { encodestr += speech_alphabet[0][pos]; } else if (speech_encoding == SPEECH_ENCODING_SPELL) { encodestr += speech_alphabet[1][pos]; } encodestr += "., "; } return encodestr; } // Spawn a sound process and block until it ends, max 5 seconds for a sound // to finish playing int SoundControl::LocalPlay(string in_player, string key) { vector<string> args; char **eargv; pid_t sndpid; int status; args = QuoteStrTokenize(in_player, " "); eargv = (char **) malloc(sizeof(char *) * (args.size() + 2)); for (unsigned int x = 0; x < args.size(); x++) { eargv[x] = strdup(args[x].c_str()); } eargv[args.size()] = strdup(key.c_str()); eargv[args.size() + 1] = NULL; if ((sndpid = fork()) == 0) { dup2(nulfd, 1); dup2(nulfd, 2); execvp(eargv[0], eargv); exit(1); } for (unsigned int x = 0; x < args.size() + 2; x++) free(eargv[x]); free(eargv); time_t play_start = time(0); // Spin waiting for the sound to end for 5 seconds, then make it end while (1) { if (waitpid(sndpid, &status, WNOHANG) == 0) { if ((time(0) - play_start) > 5) { kill(sndpid, SIGKILL); continue; } usleep(10000); } else { break; } } return 1; } // Spawn a speech process and wait for it to end, it gets more slack time than a // sound process before we kill it (20 seconds) int SoundControl::LocalSpeech(string in_speaker, int in_festival, string text) { vector<string> args; char **eargv; string speech; pid_t sndpid; int status; int pfd[2]; if (pipe(pfd) != 0) { return -1; } args = QuoteStrTokenize(in_speaker, " "); eargv = (char **) malloc(sizeof(char *) * (args.size() + 1)); for (unsigned int x = 0; x < args.size(); x++) { eargv[x] = strdup(args[x].c_str()); } eargv[args.size()] = NULL; if ((sndpid = fork()) == 0) { dup2(pfd[0], STDIN_FILENO); close(pfd[1]); dup2(nulfd, STDOUT_FILENO); dup2(nulfd, STDERR_FILENO); execvp(eargv[0], eargv); exit(1); } close(pfd[0]); // Format it for festival if (in_festival) { speech = "(SayText \"" + text + "\")\n"; } else { speech = text + "\n"; } if (write(pfd[1], text.c_str(), speech.length() + 1) < 0) _MSG(string(__FUNCTION__) + ": Failed to write speech to player: " + string(strerror(errno)), MSGFLAG_ERROR); close(pfd[1]); for (unsigned int x = 0; x < args.size() + 1; x++) free(eargv[x]); free(eargv); time_t play_start = time(0); while (1) { if (waitpid(sndpid, &status, WNOHANG) == 0) { if ((time(0) - play_start) > 30) { kill(sndpid, SIGKILL); continue; } usleep(10000); } else { break; } } return 1; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/gpscore.cc�����������������������������������������������������������������������0000664�0001750�0001750�00000020746�12124602454�015435� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "gpscore.h" #include "configfile.h" #include "soundcontrol.h" #include "packetchain.h" const char *GPS_fields_text[] = { "lat", "lon", "alt", "spd", "heading", "fix", "satinfo", "hdop", "vdop", "connected", NULL }; int Protocol_GPS(PROTO_PARMS) { GPS_data *gdata = (GPS_data *) data; for (unsigned int x = 0; x < field_vec->size(); x++) { if ((*field_vec)[x] >= GPS_maxfield) { out_string += "Unknown field requested"; return -1; } switch ((GPS_fields) (*field_vec)[x]) { case GPS_lat: out_string += gdata->lat; break; case GPS_lon: out_string += gdata->lon; break; case GPS_alt: out_string += gdata->alt; break; case GPS_spd: out_string += gdata->spd; break; case GPS_heading: out_string += gdata->heading; break; case GPS_fix: out_string += gdata->mode; break; case GPS_satinfo: out_string += gdata->satinfo; break; case GPS_hdop: out_string += gdata->hdop; break; case GPS_vdop: out_string += gdata->vdop; break; case GPS_connected: out_string += gdata->connected; break; default: out_string = "Unknown field requested."; return -1; break; } out_string += " "; } return 1; } int kis_gpspack_hook(CHAINCALL_PARMS) { // Simple packet insertion of current GPS coordinates GPSCore *cli = (GPSCore *) auxdata; // Don't bother attaching data if we're no good if (cli->FetchMode() <= 0) return 0; kis_gps_packinfo *gpsdat = new kis_gps_packinfo; // Don't override if we already have a tagged packet (like from a drone) if (in_pack->fetch(_PCM(PACK_COMP_GPS)) != NULL) return 1; cli->FetchLoc(&(gpsdat->lat), &(gpsdat->lon), &(gpsdat->alt), &(gpsdat->spd), &(gpsdat->heading), &(gpsdat->gps_fix)); in_pack->insert(_PCM(PACK_COMP_GPS), gpsdat); return 1; } GPSCore::GPSCore() { fprintf(stderr, "FATAL OOPS: GPSCore called with no globalreg\n"); exit(-1); } GPSCore::GPSCore(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: GPSCore called before packetchain\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: GPSCore called before kismet_config\n"); exit(1); } last_disconnect = 0; reconnect_attempt = -1; mode = -1; lat = lon = alt = spd = hed = last_lat = last_lon = last_hed = 0; hdop = vdop = 0; gps_ever_lock = 0; gps_connected = 0; gpseventid = -1; } GPSCore::~GPSCore() { if (gpseventid >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(gpseventid); // Unregister ourselves from the main tcp service loop globalreg->RemovePollableSubsys(this); } int GPSCore::ScanOptions() { // Lock GPS position if (globalreg->kismet_config->FetchOpt("gpsmodelock") == "true") { _MSG("Enabling GPS position information override (override broken GPS " "units that always report 0 in the NMEA stream)", MSGFLAG_INFO); SetOptions(GPSD_OPT_FORCEMODE); } if (globalreg->kismet_config->FetchOpt("gpsreconnect") == "true") { _MSG("Enabling reconnection to the GPS device if the link is lost", MSGFLAG_INFO); reconnect_attempt = 0; } return 1; } int GPSCore::RegisterComponents() { // Register the network protocol gps_proto_ref = globalreg->kisnetserver->RegisterProtocol("GPS", 0, 0, GPS_fields_text, &Protocol_GPS, NULL, this); // Register the gps component and packetchain hooks to include it _PCM(PACK_COMP_GPS) = globalreg->packetchain->RegisterPacketComponent("gps"); globalreg->packetchain->RegisterHandler(&kis_gpspack_hook, this, CHAINPOS_POSTCAP, -100); return 1; } int GPSCore::FetchLoc(double *in_lat, double *in_lon, double *in_alt, double *in_spd, double *in_hed, int *in_mode) { *in_lat = lat; *in_lon = lon; *in_alt = alt; *in_spd = spd; *in_mode = mode; *in_hed = hed; return mode; } double GPSCore::CalcHeading(double in_lat, double in_lon, double in_lat2, double in_lon2) { double r = CalcRad((double) in_lat2); double lat1 = Deg2Rad((double) in_lat); double lon1 = Deg2Rad((double) in_lon); double lat2 = Deg2Rad((double) in_lat2); double lon2 = Deg2Rad((double) in_lon2); double angle = 0; if (lat1 == lat2) { if (lon2 > lon1) { angle = M_PI/2; } else if (lon2 < lon1) { angle = 3 * M_PI / 2; } else { return 0; } } else if (lon1 == lon2) { if (lat2 > lat1) { angle = 0; } else if (lat2 < lat1) { angle = M_PI; } } else { double tx = r * cos((double) lat1) * (lon2 - lon1); double ty = r * (lat2 - lat1); angle = atan((double) (tx/ty)); if (ty < 0) { angle += M_PI; } if (angle >= (2 * M_PI)) { angle -= (2 * M_PI); } if (angle < 0) { angle += 2 * M_PI; } } return (double) Rad2Deg(angle); } double GPSCore::Rad2Deg(double x) { return (x/M_PI) * 180.0; } double GPSCore::Deg2Rad(double x) { return 180/(x*M_PI); } double GPSCore::EarthDistance(double in_lat, double in_lon, double in_lat2, double in_lon2) { double x1 = CalcRad(in_lat) * cos(Deg2Rad(in_lon)) * sin(Deg2Rad(90-in_lat)); double x2 = CalcRad(in_lat2) * cos(Deg2Rad(in_lon2)) * sin(Deg2Rad(90-in_lat2)); double y1 = CalcRad(in_lat) * sin(Deg2Rad(in_lon)) * sin(Deg2Rad(90-in_lat)); double y2 = CalcRad(in_lat2) * sin(Deg2Rad(in_lon2)) * sin(Deg2Rad(90-in_lat2)); double z1 = CalcRad(in_lat) * cos(Deg2Rad(90-in_lat)); double z2 = CalcRad(in_lat2) * cos(Deg2Rad(90-in_lat2)); double a = acos((x1*x2 + y1*y2 + z1*z2)/pow(CalcRad((double) (in_lat+in_lat2)/2),2)); return CalcRad((double) (in_lat+in_lat2) / 2) * a; } double GPSCore::CalcRad(double lat) { double a = 6378.137, r, sc, x, y, z; double e2 = 0.081082 * 0.081082; lat = lat * M_PI / 180.0; sc = sin (lat); x = a * (1.0 - e2); z = 1.0 - e2 * sc * sc; y = pow (z, 1.5); r = x / y; r = r * 1000.0; return r; } int GPSCore::Timer() { // Pick up if we've ever locked in if (mode >= 2) gps_ever_lock = 1; // Always send info GPS_data gdata; gdata.lat = NtoString<double>(lat, 6).Str(); gdata.lon = NtoString<double>(lon, 6).Str(); gdata.alt = NtoString<double>(alt).Str(); gdata.spd = NtoString<double>(spd).Str(); gdata.heading = NtoString<double>(hed).Str(); gdata.mode = last_disconnect == 0 ? IntToString(mode) : "0"; gdata.hdop = NtoString<double>(hdop).Str(); gdata.vdop = NtoString<double>(vdop).Str(); gdata.connected = (gps_connected == 1 && last_disconnect == 0) ? "1" : "0"; gdata.satinfo = "\001"; for (map<int, sat_pos>::iterator x = sat_pos_map.begin(); x != sat_pos_map.end(); ++x) { gdata.satinfo += IntToString(x->second.prn) + string(":") + IntToString(x->second.elevation) + string(":") + IntToString(x->second.azimuth) + string(":") + IntToString(x->second.snr) + string(","); } gdata.satinfo += "\001"; globalreg->kisnetserver->SendToAll(gps_proto_ref, (void *) &gdata); // Make an empty packet w/ just GPS data for the gpsxml logger to catch kis_packet *newpack = globalreg->packetchain->GeneratePacket(); kis_gps_packinfo *gpsdat = new kis_gps_packinfo; newpack->ts.tv_sec = globalreg->timestamp.tv_sec; newpack->ts.tv_usec = globalreg->timestamp.tv_usec; FetchLoc(&(gpsdat->lat), &(gpsdat->lon), &(gpsdat->alt), &(gpsdat->spd), &(gpsdat->heading), &(gpsdat->gps_fix)); newpack->insert(_PCM(PACK_COMP_GPS), gpsdat); globalreg->packetchain->ProcessPacket(newpack); return 1; } ��������������������������kismet-2013-03-R1b/dumpfile_tuntap.h����������������������������������������������������������������0000664�0001750�0001750�00000006316�12124602454�017032� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_TUNTAP_H__ #define __DUMPFILE_TUNTAP_H__ /* * TUN/TAP dumpfile module * * This writes 802.11 frames to the userspace end of a tun/tap virtual network * device. Any other packet capture device can attach to this interface then * and get a runtime packet stream from Kismet, which is really cool. This is * much less fragile than the named pipe output, because Kismet doesn't care * what is listening to the interface or when. * * This currently only works on Linux, but should be portable to any system * which supports the tun/tap interface model (BSD and OSX should). * * To work fully on Linux it needs a patch which will, with luck, be mainlained * eventually. Without the patch, the tap device will always be a en10mb link * type, which will confuse pcap and anything sniffing since it's not en10mb * frames. Any listening device SHOULD be able to retranslate to a different * link type, but the kernel patch solves this problem fully. * * This is a bizzare not-quite-normal dumpfile module. It doesn't parse the * normal dumptypes string, and it has to be started before the root privdrop. * It's closer to a dumpfile than anything else though, and the flush/close/ * track system isn't worth duplicating. */ #include "config.h" #include <string> #include <stdio.h> #include <stdlib.h> #include <ctype.h> /* Linux system includes */ #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/ioctl.h> #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "dumpfile.h" #ifdef SYS_LINUX #include <linux/if_tun.h> // Linux IEEE80211 link typ to set #define LNX_LINKTYPE_80211 801 // If the system headers don't have the TUNSETLINK ioctl, define it here, // and we'll figure it out at runtime #ifndef TUNSETLINK #define TUNSETLINK _IOW('T', 205, int) #endif #endif struct ipc_dft_open { uint8_t tapdevice[32]; }; // Hook for grabbing packets int dumpfiletuntap_chain_hook(CHAINCALL_PARMS); // Pcap-based packet writer class Dumpfile_Tuntap : public Dumpfile { public: Dumpfile_Tuntap(); Dumpfile_Tuntap(GlobalRegistry *in_globalreg); virtual ~Dumpfile_Tuntap(); virtual int OpenTuntap(); virtual int GetTapFd(); virtual void SetTapDevice(string in_dev) { fname = in_dev; } virtual void RegisterIPC(); virtual int chain_handler(kis_packet *in_pack); virtual int Flush(); protected: int tuntap_fd; int ipc_sync_id, ipc_trigger_id; }; #endif /* __dump... */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/madwifing_control.h��������������������������������������������������������������0000664�0001750�0001750�00000003234�12124602454�017333� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <vector> #include <string> #ifndef __MADWIFING_CONFIG__ #define __MADWIFING_CONFIG__ #ifdef SYS_LINUX /* Madwifi NG ioctls from net80211 */ #define SIOC80211IFCREATE (SIOCDEVPRIVATE+7) #define SIOC80211IFDESTROY (SIOCDEVPRIVATE+8) #define IEEE80211_CLONE_BSSID 0x0001 #define IEEE80211_NO_STABEACONS 0x0002 #define IEEE80211_M_STA 1 #define IEEE80211_M_IBSS 0 #define IEEE80211_M_MASTER 6 #define IEEE80211_M_MONITOR 8 /* Get a list of all vaps on an interface */ int madwifing_list_vaps(const char *ifname, vector<string> *retvec); /* Get the parent interface index in a vap list */ int madwifing_find_parent(vector<string> *vaplist); /* Destroy a vap */ int madwifing_destroy_vap(const char *ifname, char *errstr); /* Make a vap */ int madwifing_build_vap(const char *ifname, char *errstr, const char *vapname, char *retvapname, int vapmode, int vapflags); #endif /* linux */ #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/popenclient.h��������������������������������������������������������������������0000664�0001750�0001750�00000004346�12124602454�016153� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __POPENCLIENT_H__ #define __POPENCLIENT_H__ #include "config.h" #include <stdio.h> #include <string> #include <time.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> #include <map> #include <vector> #include <termios.h> #include "ringbuf.h" #include "messagebus.h" #include "timetracker.h" #include "clinetframework.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif // Arbitrary 16k ring. #define POPEN_RING_LEN (16384) class PopenClient : public NetworkClient { public: PopenClient(); PopenClient(GlobalRegistry *in_globalreg); virtual ~PopenClient(); virtual int CheckPidVec(); // Bastardized Connect() overload - remotehost used as path to program, // port expected to be a char 'r' or 'w' virtual int Connect(const char *in_remotehost, short int in_port, netcli_connect_cb in_connect_cb, void *in_con_aux); virtual void KillConnection(); virtual void SoftKillConnection(); virtual void DetatchConnection(); virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); protected: virtual int Validate() { return 1; } // Stdin/out/err pipe pairs int ipipe[2], opipe[2], epipe[2]; pid_t childpid; virtual int ReadBytes(); virtual int ReadEBytes(); virtual int WriteBytes(); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/darwin_wificontrol.h�������������������������������������������������������������0000664�0001750�0001750�00000002624�12124602454�017533� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define __IN_OBJC_FILE__ #import <Foundation/Foundation.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include "apple80211.h" #include <Carbon/Carbon.h> #include "darwin_control_wrapper.h" @interface DarwinWifi: NSObject { id iface; NSAutoreleasePool *pool; NSBundle *bundle; Class CWI_class; NSString *ifname; WirelessContextPtr *ctx; } -(DarwinWifi *) initWithInterface: (NSString *) n; -(BOOL) getSupportMonitor; -(void) setIfname: (NSString *) n; -(void) setPool; -(void) setBundle; -(NSArray *) getSupportedChannels; -(BOOL) setChannel: (unsigned int) c error: (char *) e; -(BOOL) getCoreWireless; -(void) disAssociate; @end; ������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/cygwin_utils.h�������������������������������������������������������������������0000664�0001750�0001750�00000003316�12124602454�016347� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file was written by Loris Degioanni, and is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef __CYGWIN_UTILS_H__ #define __CYGWIN_UTILS_H__ #ifdef SYS_CYGWIN #include <sys/time.h> #include <sys/types.h> #include <unistd.h> class Handle2Fd { public: Handle2Fd(); ~Handle2Fd(); int AddHandle(HANDLE h); void Signalread(); int Activate(); void Reset(); int GetFd(); int MergeSet(fd_set *set, int max); int IsEventSet(unsigned int HandleNumber); private: #ifdef HANDLE2FD_INTERNAL // The Unix side of cygwin doesn't like this static DWORD WINAPI WaitThread(LPVOID lpParameter); CRITICAL_SECTION PipeCs; HANDLE WinHandles[MAXIMUM_WAIT_OBJECTS + 1]; #endif void SetPipe(); void ResetPipe(); int PipeFds[2]; unsigned int NHandles; HANDLE WaitThreadHandle; HANDLE ReadEvent; int ThreadAlive; int PipeSignalled; char ResetBuf[300]; int FirstFdSet; }; #endif /* sys_cygwin */ #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/globalregistry.cc����������������������������������������������������������������0000664�0001750�0001750�00000010375�12124602454�017021� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <unistd.h> #include "globalregistry.h" #include "util.h" #include "macaddr.h" #include "dumpfile.h" GlobalRegistry::GlobalRegistry() { fatal_condition = 0; spindown = 0; winch = false; argc = 0; argv = NULL; envp = NULL; kismet_instance = KISMET_INSTANCE_SERVER; getopt_long_num = 127; next_ext_ref = 0; messagebus = NULL; plugintracker = NULL; sourcetracker = NULL; netracker = NULL; packetchain = NULL; alertracker = NULL; timetracker = NULL; kisnetserver = NULL; kisdroneserver = NULL; kismet_config = NULL; kismetui_config = NULL; soundctl = NULL; builtindissector = NULL; rootipc = NULL; panel_interface = NULL; manufdb = NULL; start_time = 0; metric = 0; for (int x = 0; x < PROTO_REF_MAX; x++) netproto_map[x] = -1; filter_tracker = 0; filter_tracker_bssid_invert = -1; filter_tracker_source_invert = -1; filter_tracker_dest_invert = -1; filter_dump = 0; filter_dump_bssid_invert = -1; filter_dump_source_invert = -1; filter_dump_dest_invert = -1; filter_export = 0; filter_export_bssid_invert = -1; filter_export_source_invert = -1; filter_export_dest_invert = -1; broadcast_mac = mac_addr("FF:FF:FF:FF:FF:FF"); alert_backlog = 0; for (unsigned int x = 0; x < PACK_COMP_MAX; x++) packetcomp_map[x] = -1; for (unsigned int x = 0; x < ALERT_REF_MAX; x++) alertref_map[x] = -1; pcapdump = NULL; nlhandle = NULL; checksum_packets = 0; } // External globals -- allow other things to tie structs to us int GlobalRegistry::RegisterGlobal(string in_name) { map<string, int>::iterator i; if ((i = ext_name_map.find(StrLower(in_name))) != ext_name_map.end()) return i->second; ext_name_map[StrLower(in_name)] = next_ext_ref++; return next_ext_ref; } int GlobalRegistry::FetchGlobalRef(string in_name) { if (ext_name_map.find(StrLower(in_name)) == ext_name_map.end()) return -1; return ext_name_map[StrLower(in_name)]; } void *GlobalRegistry::FetchGlobal(int in_ref) { if (ext_data_map.find(in_ref) == ext_data_map.end()) return NULL; return ext_data_map[in_ref]; } void *GlobalRegistry::FetchGlobal(string in_name) { int ref; if ((ref = FetchGlobalRef(in_name)) < 0) return NULL; return ext_data_map[ref]; } int GlobalRegistry::InsertGlobal(int in_ref, void *in_data) { if (ext_data_map.find(in_ref) == ext_data_map.end()) return -1; ext_data_map[in_ref] = in_data; return 1; } int GlobalRegistry::InsertGlobal(string in_name, void *in_data) { int ref = RegisterGlobal(in_name); return InsertGlobal(ref, in_data); } int GlobalRegistry::RegisterPollableSubsys(Pollable *in_subcli) { subsys_pollable_vec.push_back(in_subcli); return 1; } int GlobalRegistry::RemovePollableSubsys(Pollable *in_subcli) { for (unsigned int x = 0; x < subsys_pollable_vec.size(); x++) { if (subsys_pollable_vec[x] == in_subcli) { subsys_pollable_vec.erase(subsys_pollable_vec.begin() + x); return 1; } } return 0; } void GlobalRegistry::RegisterDumpFile(Dumpfile *in_dump) { subsys_dumpfile_vec.push_back(in_dump); } int GlobalRegistry::RemoveDumpFile(Dumpfile *in_dump) { for (unsigned int x = 0; x < subsys_dumpfile_vec.size(); x++) { if (subsys_dumpfile_vec[x] == in_dump) { subsys_dumpfile_vec.erase(subsys_dumpfile_vec.begin() + x); return 1; } } return 0; } Dumpfile *GlobalRegistry::FindDumpFileType(string in_type) { string type = StrUpper(in_type); for (unsigned int x = 0; x < subsys_dumpfile_vec.size(); x++) { if (StrUpper(subsys_dumpfile_vec[x]->FetchFileType()) == type) { return subsys_dumpfile_vec[x]; } } return NULL; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/kismet_json.h��������������������������������������������������������������������0000664�0001750�0001750�00000010317�12124602454�016153� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KISMET_JSON_H__ #define __KISMET_JSON_H__ #include "config.h" #include <stdio.h> #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <pwd.h> #include <ctype.h> #include <math.h> #include <string> #include <map> #include <vector> #include <list> #include <sstream> #include <iomanip> #include "util.h" // Basic JSON interpreter - understands numbers, floats, quoted strings, bools, // arrays, dictionaries, arbitrary nesting. Currently sufficient for parsing // from GPSD, may be extended for other protocols in the future // // JSON is annoyingly complex, requiring a full lex and parse process. enum JSON_token_type { JSON_start, JSON_end, JSON_quoted, JSON_numeric, JSON_boolean, JSON_arrstart, JSON_arrend, JSON_colon, JSON_comma, // Meta-types for expected values JSON_sep, JSON_value, JSON_sym, JSON_unknown }; struct JSON_token { JSON_token_type tok_type; string tok_str; int tok_position; }; struct JSON_value { JSON_token value; // Dictionary of values, used for parents. Values may in turn be // dictionaries or arrays map<string, struct JSON_value *> value_map; // If we're an array, the array of our values is here. We can't be // both a dictionary and an array. vector<struct JSON_value *> value_array; }; // Recursively free a JSON value void JSON_delete(struct JSON_value *v); // Parse a JSON string into a value struct. // How value structs work: // A basic JSON structure is a dictionary which holds multiple symbol => value maps. // A value can be a string, int, float, bool, a sub-dictionary, or a sub-array. // An array can also hold multiple dictionaries as values. Arrays are not forced to // hold all values of a single type, [1.2345, false, "foo"] is considered valid by // this parser. // // Once parsed, the JSON_value returned struct is the top level dictionary. Values // stored in this dictionary can be found in value_map keyed by their symbols. // // When a value is extracted from value_map, value.tok_type should be checked to // determine what kind of value it is. JSON_quoted, _numeric, _boolean contain // their values in value.tok_str as an unchecked string (numbers and bools should // be valid because they passed the lexer, but the caller should perform safe // transforms anyhow). // // Nested dictionaries are stored as value.tok_type JSON_start, and nested arrays // are stored as JSON_arrstart. The values contained in the nested structure are // stored in value_map and value_array, respectively. // // Complex JSON data may require crawling through multiple levels of the dictionary // and array maps, examine the GPSD or look at the JSON_display() example function. struct JSON_value *JSON_parse(string in_json, string& error); struct JSON_value *JSON_dict_get_value(struct JSON_value *in_parent, string in_key, string& error); // Some basic JSON extraction functions for common actions string JSON_dict_get_string(struct JSON_value *in_parent, string in_key, string& error); // Always return a float, cast it to an int if you need to, can be used // for bools too (you get a 0 or 1) float JSON_dict_get_number(struct JSON_value *in_parent, string in_key, string& error); // Example function which dumps to stdout a representation of the parsed JSON data void JSON_dump(struct JSON_value *jsonv, string key, int depth); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/filtercore.cc��������������������������������������������������������������������0000664�0001750�0001750�00000052443�12124602454�016130� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <sstream> #include "util.h" #include "filtercore.h" FilterCore::FilterCore() { fprintf(stderr, "FATAL OOPS: FilterCore() called w/ no globalreg\n"); exit(1); } FilterCore::FilterCore(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; bssid_invert = -1; source_invert = -1; dest_invert = -1; bssid_hit = 0; source_hit = 0; dest_hit = 0; #ifdef HAVE_LIBPCRE pcre_invert = -1; pcre_hit = 0; #endif } #define _filter_stacker_none 0 #define _filter_stacker_mac 1 #define _filter_stacker_pcre 2 #define _filter_type_none -1 #define _filter_type_bssid 0 #define _filter_type_source 1 #define _filter_type_dest 2 #define _filter_type_any 3 #define _filter_type_pcre 4 int FilterCore::AddFilterLine(string filter_str) { _kis_lex_rec ltop; int type = _filter_stacker_none; int mtype = _filter_type_none; int negate = -1; string errstr; // Local copies to add so we can error out cleanly... This is a cheap // hack but it lets us avoid a bunch of if's map<int, vector<mac_addr> > local_maps; map<int, int> local_inverts; #ifdef HAVE_LIBPCRE vector<pcre_filter *> local_pcre; #endif vector<mac_addr> macvec; local_inverts[_filter_type_bssid] = -1; local_inverts[_filter_type_source] = -1; local_inverts[_filter_type_dest] = -1; local_inverts[_filter_type_any] = -1; local_inverts[_filter_type_pcre] = -1; list<_kis_lex_rec> precs = LexString(filter_str, errstr); if (precs.size() == 0) { _MSG(errstr, MSGFLAG_ERROR); return -1; } while (precs.size() > 0) { // Grab the top of the stack, pop the lexer ltop = precs.front(); precs.pop_front(); // Ignore 'none' if (ltop.type == _kis_lex_none) { continue; } // If we don't have anything in the stack... if (type == _filter_stacker_none) { // Ignore delimiters, they just break up mac addresses if (ltop.type == _kis_lex_delim) continue; if (ltop.type != _kis_lex_string) { _MSG("Couldn't parse filter line '" + filter_str + "', expected an " "unquoted string", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } string uqstr = StrLower(ltop.data); if (uqstr == "bssid") { type = _filter_stacker_mac; mtype = _filter_type_bssid; } else if (uqstr == "source") { type = _filter_stacker_mac; mtype = _filter_type_source; } else if (uqstr == "dest") { type = _filter_stacker_mac; mtype = _filter_type_dest; } else if (uqstr == "any") { type = _filter_stacker_mac; mtype = _filter_type_any; } else if (uqstr == "pcre") { type = _filter_stacker_pcre; } else { _MSG("Couldn't parse filter line '" + filter_str + "', expected one " "of BSSID, SOURCE, DEST, ANY, PCRE", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } // check for a '(' if (precs.size() <= 0) { _MSG("Couldn't parse filter line '" + filter_str + "', expected (", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } ltop = precs.front(); precs.pop_front(); if (ltop.type != _kis_lex_popen) { _MSG("Couldn't parse filter line '" + filter_str + "', expected (", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } // Peek for a negation if (precs.size() <= 0) { _MSG("Couldn't parse filter line '" + filter_str + "', expected " "contents", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } continue; } if (type == _filter_stacker_mac) { int addr_loc_negate = 0; if (ltop.type == _kis_lex_negate) { if (negate == 0) { _MSG("Couldn't parse filter line '" + filter_str + "', cannot " "mix negated and non-negated MAC addresses on the same " "filter", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif } // Double-hop on negates negate = 1; addr_loc_negate = 1; ltop = precs.front(); precs.pop_front(); } // Look for an address as a string if (ltop.type != _kis_lex_string) { _MSG("Couldn't parse filter line '" + filter_str + "', expected " "MAC address", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } if (negate == 1 && addr_loc_negate != 1) { _MSG("Couldn't parse filter line '" + filter_str + "', cannot " "mix inverted and non-inverted MAC addresses on the same " "filter", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } mac_addr mymac = ltop.data.c_str(); if (mymac.error) { _MSG("Couldn't parse filter line '" + filter_str + "', expected " "MAC address and could not interpret '" + ltop.data + "'", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } // Add it to the local map for this type (local_maps[mtype]).push_back(mymac); // Peek at the next item if (precs.size() <= 0) { _MSG("Couldn't parse filter line '" + filter_str + "', expected ',' " "or ')'", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } ltop = precs.front(); precs.pop_front(); // If it's a delimiter, skip over it and continue if (ltop.type == _kis_lex_delim) continue; // if it's a close paren, close down and save/errorcheck the negation if (ltop.type == _kis_lex_pclose) { if (local_inverts[mtype] != -1 && local_inverts[mtype] != negate) { _MSG("Couldn't parse filter line '" + filter_str + "', filter " "has an illegal mix of normal and inverted addresses. " "A filter type must be either all inverted addresses or all " "standard addresses.", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } if (negate < 0) negate = 0; local_inverts[mtype] = negate; type = _filter_stacker_none; mtype = _filter_type_none; negate = 0; continue; } // Fall through and hit errors about anything else _MSG("Couldn't parse filter line '" + filter_str + "', expected ',' " "or ')'", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } if (type == _filter_stacker_pcre) { #ifndef HAVE_LIBPCRE // Catch libpcre not being here _MSG("Couldn't parse filter line '" + filter_str + "', filter " "uses PCRE regular expressions and this instance of Kismet " "was not compiled with libpcre support.", MSGFLAG_ERROR); return -1; #else // Look for a quoted string if (ltop.type != _kis_lex_quotestring) { _MSG("Couldn't parse filter line '" + filter_str + "', expected " "quoted string", MSGFLAG_ERROR); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; } // local_pcre.push_back(ltop.data); // Try to parse and study the PCRE pcre_filter *filt = new pcre_filter; const char *error, *study_err; int erroffset; ostringstream osstr; filt->re = pcre_compile(ltop.data.c_str(), 0, &error, &erroffset, NULL); if (filt->re == NULL) { osstr << "Couldn't parse filter line '" << filter_str << "', PCRE " "compilation failure '" << error << "' at offset " << erroffset; _MSG(osstr.str(), MSGFLAG_ERROR); delete(filt); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; } filt->study = pcre_study(filt->re, 0, &study_err); if (filt->study != NULL) { osstr << "Couldn't parse filter line '" << filter_str << "', PCRE " "study/optimization failure '" << study_err << "'"; _MSG(osstr.str(), MSGFLAG_ERROR); pcre_free(filt->re); delete(filt); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; } filt->filter = ltop.data; local_pcre.push_back(filt); // Peek at the next item if (precs.size() <= 0) { _MSG("Couldn't parse filter line '" + filter_str + "', expected ',' " "or ')'", MSGFLAG_ERROR); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; } ltop = precs.front(); precs.pop_front(); // If it's a delimiter, skip over it and continue if (ltop.type == _kis_lex_delim) { continue; } // If it's a close paren, close down if (ltop.type == _kis_lex_pclose) { if (local_inverts[_filter_type_pcre] != -1 && local_inverts[_filter_type_pcre] != negate) { _MSG("Couldn't parse filter line '" + filter_str + "', filter " "has an illegal mix of normal and inverted PCRE filters. " "A filter type must be either all inverted addresses or all " "standard addresses.", MSGFLAG_ERROR); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; } local_inverts[_filter_type_pcre] = negate; type = _filter_stacker_none; mtype = _filter_type_none; negate = 0; continue; } // Fall through and hit errors about anything else _MSG("Couldn't parse filter line '" + filter_str + "', expected ',' " "or ')'", MSGFLAG_ERROR); for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } return -1; #endif } } // Check all the negate joins before we edit anything int negfail = 0; negate = local_inverts[_filter_type_bssid]; if (negate != -1) { macvec = local_maps[_filter_type_bssid]; if (bssid_invert != -1 && negate != bssid_invert) { negfail = 1; } } negate = local_inverts[_filter_type_source]; if (negate != -1) { macvec = local_maps[_filter_type_source]; if (source_invert != -1 && negate != source_invert) { negfail = 1; } } negate = local_inverts[_filter_type_dest]; if (negate != -1) { macvec = local_maps[_filter_type_dest]; if (dest_invert != -1 && negate != dest_invert) { negfail = 1; } } negate = local_inverts[_filter_type_any]; if (negate != -1) { macvec = local_maps[_filter_type_any]; if ((dest_invert != 1 && negate != dest_invert) || (source_invert != 1 && negate != source_invert) || (bssid_invert != 1 && negate != bssid_invert)) { _MSG("Couldn't parse filter line '" + filter_str + "', filter uses the " "ANY filter term. The ANY filter can only be used on inverted " "matches to discard any packets not matching the specified address, " "and the DEST, SOURCE, and BSSID filter terms must contain only " "inverted matches.", MSGFLAG_ERROR); negfail = 1; } } #ifdef HAVE_LIBPCRE negate = local_inverts[_filter_type_pcre]; if (negate != -1) { macvec = local_maps[_filter_type_pcre]; if (pcre_invert != -1 && negate != pcre_invert) { negfail = 1; } } #endif if (negfail != 0) { _MSG("Couldn't parse filter line '" + filter_str + "', filter " "has an illegal mix of normal and inverted addresses. " "A filter type must be either all inverted addresses or all " "standard addresses.", MSGFLAG_ERROR); #ifdef HAVE_LIBPCRE for (unsigned zed = 0; zed < local_pcre.size(); zed++) { pcre_free(local_pcre[zed]->re); pcre_free(local_pcre[zed]->study); delete(local_pcre[zed]); } #endif return -1; } // Join all the maps back up with the real filters negate = local_inverts[_filter_type_bssid]; if (negate != -1) { macvec = local_maps[_filter_type_bssid]; bssid_invert = negate; for (unsigned int x = 0; x < macvec.size(); x++) { bssid_map.insert(macvec[x], 1); } } negate = local_inverts[_filter_type_source]; if (negate != -1) { macvec = local_maps[_filter_type_source]; source_invert = negate; for (unsigned int x = 0; x < macvec.size(); x++) { source_map.insert(macvec[x], 1); } } negate = local_inverts[_filter_type_dest]; if (negate != -1) { macvec = local_maps[_filter_type_dest]; dest_invert = negate; for (unsigned int x = 0; x < macvec.size(); x++) { dest_map.insert(macvec[x], 1); } } negate = local_inverts[_filter_type_any]; if (negate != -1) { macvec = local_maps[_filter_type_any]; for (unsigned int x = 0; x < macvec.size(); x++) { dest_map.insert(macvec[x], 1); source_map.insert(macvec[x], 1); bssid_map.insert(macvec[x], 1); } } #ifdef HAVE_LIBPCRE negate = local_inverts[_filter_type_pcre]; if (negate != -1) { pcre_invert = negate; for (unsigned int x = 0; x < local_pcre.size(); x++) { pcre_vec.push_back(local_pcre[x]); } } #endif return 1; #if 0 // Break it into filter terms size_t parse_pos = 0; size_t parse_error = 0; while (parse_pos < filter_str.length()) { size_t addr_term_end; size_t address_target = 0; // 1=bssid 2=source 4=dest 7=any if (filter_str[parse_pos] == ',' || filter_str[parse_pos] == ' ') { parse_pos++; continue; } if ((addr_term_end = filter_str.find('(', parse_pos + 1)) == string::npos) { _MSG("Couldn't parse filter line '" + filter_str + "' no '(' found", MSGFLAG_ERROR); parse_error = 1; break; } string addr_term = StrLower(filter_str.substr(parse_pos, addr_term_end - parse_pos)); parse_pos = addr_term_end + 1; if (addr_term.length() == 0) { _MSG("Couldn't parse filter line '" + filter_str + "' no address type " "given.", MSGFLAG_ERROR); parse_error = 1; break; } if (addr_term == "any") { address_target = 7; } else if (addr_term == "bssid") { address_target = 1; } else if (addr_term == "source") { address_target = 2; } else if (addr_term == "dest") { address_target = 4; } else { _MSG("Couldn't parse filter line '" + filter_str + "' unknown address " "type '" + addr_term + "' (expected 'any', 'bssid', 'source', " "'dest'", MSGFLAG_ERROR); parse_error = 1; break; } if ((addr_term_end = filter_str.find(')', parse_pos + 1)) == string::npos) { _MSG("Couldn't parse filter line '" + filter_str + "', no ')' found", MSGFLAG_ERROR); parse_error = 1; break; } string term_contents = filter_str.substr(parse_pos, addr_term_end - parse_pos); parse_pos = addr_term_end + 1; if (term_contents.length() == 0) { _MSG("Couldn't parse filter line '" + filter_str + "' no addresses " "listed after address type", MSGFLAG_ERROR); parse_error = 1; break; } size_t term_parse_pos = 0; while (term_parse_pos < term_contents.length()) { size_t term_end; int invert = 0; if (term_contents[term_parse_pos] == ' ' || term_contents[term_parse_pos] == ',') { term_parse_pos++; continue; } if (term_contents[term_parse_pos] == '!') { invert = 1; term_parse_pos++; } if ((term_end = term_contents.find(',', term_parse_pos + 1)) == string::npos) term_end = term_contents.length(); string single_addr = term_contents.substr(term_parse_pos, term_end - term_parse_pos); mac_addr mac = single_addr.c_str(); if (mac.error != 0) { _MSG("Couldn't parse filter string '" + filter_str + "' MAC " "address '" + single_addr + "'", MSGFLAG_ERROR); parse_error = 1; break; } // Catch non-inverted 'ANY' if (address_target == 7 && invert == 0) { _MSG("Filtering address type 'ANY' will discard all packets. The " "'ANY' address type can only be used on inverted matches to " "discard any packets not matching the specified.", MSGFLAG_ERROR); parse_error = 1; break; } // Do an insert check for mismatched inversion flags, set it, // and set the inversion for future address types if (address_target & 0x01) { if (bssid_invert != -1 && invert != bssid_invert) { _MSG("BSSID filter '" + filter_str + "' has an illegal mix of " "normal and inverted addresses. A filter must be either " "all inverted addresses or all standard addresses.", MSGFLAG_ERROR); return -1; } bssid_map.insert(mac, invert); bssid_invert = invert; } if (address_target & 0x02) { if (source_invert != -1 && invert != source_invert) { _MSG("SOURCE filter '" + filter_str + "' has an illegal mix of " "normal and inverted addresses. A filter must be either " "all inverted addresses or all standard addresses.", MSGFLAG_ERROR); return -1; } source_map.insert(mac, invert); source_invert = invert; } if (address_target & 0x04) { if (dest_invert != -1 && invert != dest_invert) { _MSG("DEST filter '" + filter_str + "' has an illegal mix of " "normal and inverted addresses. A filter must be either " "all inverted addresses or all standard addresses.", MSGFLAG_ERROR); return -1; } dest_map.insert(mac, invert); dest_invert = invert; } term_parse_pos = term_end + 1; } } if (parse_error == 1) return -1; return 1; #endif } int FilterCore::RunFilter(mac_addr bssidmac, mac_addr sourcemac, mac_addr destmac) { int hit = 0; // Clumsy artifact of how iters are defined for macmap currently, must // be defined as an assign macmap<int>::iterator fitr = bssid_map.find(bssidmac); if ((fitr != bssid_map.end() && bssid_invert == 1) || (fitr == bssid_map.end() && bssid_invert == 0)) { bssid_hit++; hit = 1; } fitr = source_map.find(sourcemac); if ((fitr != source_map.end() && source_invert == 1) || (fitr == source_map.end() && source_invert == 0)) { source_hit++; hit = 1; } fitr = dest_map.find(destmac); if ((fitr != dest_map.end() && dest_invert == 1) || (fitr == dest_map.end() && dest_invert == 0)) { dest_hit++; hit = 1; } return hit; } int FilterCore::FetchPCREHits() { #ifndef HAVE_LIBPCRE return 0; #else return pcre_hit; #endif } int FilterCore::RunPcreFilter(string in_text) { #ifndef HAVE_LIBPCRE return 0; #else int ovector[128]; int rc; for (unsigned int x = 0; x < pcre_vec.size(); x++) { rc = pcre_exec(pcre_vec[x]->re, pcre_vec[x]->study, in_text.c_str(), in_text.length(), 0, 0, ovector, 128); if ((rc >= 0 && pcre_invert == 0) || (rc < 0 && pcre_invert == 1)) return 1; } #endif return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/dumpfile_string.h����������������������������������������������������������������0000664�0001750�0001750�00000002572�12124602454�017025� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_STRING_H__ #define __DUMPFILE_STRING_H__ #include "config.h" #include <stdio.h> #include <string> #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "packetdissectors.h" #include "dumpfile.h" // Hook for grabbing packets int dumpfilestring_chain_hook(CHAINCALL_PARMS); // Pcap-based packet writer class Dumpfile_String : public Dumpfile { public: Dumpfile_String(); Dumpfile_String(GlobalRegistry *in_globalreg); virtual ~Dumpfile_String(); virtual int chain_handler(kis_packet *in_pack); virtual int Flush(); protected: FILE *stringfile; }; #endif /* __dump... */ ��������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/globalregistry.h�����������������������������������������������������������������0000664�0001750�0001750�00000020455�12124602454�016663� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __GLOBALREGISTRY_H__ #define __GLOBALREGISTRY_H__ #include "config.h" #include <unistd.h> #include "util.h" #include "macaddr.h" // #include "packet.h" // Pre-defs for all the things we point to class MessageBus; class Packetsourcetracker; // Old network tracking core due to be removed class Netracker; // new multiphy tracking core class Devicetracker; class Packetchain; class Alertracker; class Timetracker; class KisNetFramework; class KisDroneFramework; class ConfigFile; class GroupConfigFile; class SoundControl; class Plugintracker; class KisBuiltinDissector; // We need these for the vectors of subservices to poll class Pollable; // Vector of dumpfiles to destroy class Dumpfile; // ipc system class IPCRemote; class RootIPCRemote; class KisPanelInterface; // Manuf db class Manuf; // Pcap dump (only built-in dumpfile which supports plugin hooks currently) class Dumpfile_Pcap; #define KISMET_INSTANCE_SERVER 0 #define KISMET_INSTANCE_DRONE 1 #define KISMET_INSTANCE_CLIENT 2 // These are the offsets into the array of protocol references, not // the reference itself. // tcpserver protocol numbers for all the builtin protocols kismet // uses and needs to refer to internally. Modules are on their own // for tracking this. #define PROTO_REF_KISMET 0 #define PROTO_REF_ERROR 1 #define PROTO_REF_ACK 2 #define PROTO_REF_PROTOCOL 3 #define PROTO_REF_CAPABILITY 4 #define PROTO_REF_TERMINATE 5 #define PROTO_REF_TIME 6 #define PROTO_REF_BSSID 7 #define PROTO_REF_CLIENT 8 #define PROTO_REF_CARD 9 #define PROTO_REF_GPS 10 #define PROTO_REF_ALERT 11 #define PROTO_REF_STATUS 12 #define PROTO_REF_INFO 13 #define PROTO_REF_REMOVE 14 #define PROTO_REF_PACKET 15 #define PROTO_REF_STRING 16 #define PROTO_REF_WEPKEY 17 #define PROTO_REF_SSID 18 #define PROTO_REF_MAX 19 // Same game, packet component references #define PACK_COMP_80211 0 #define PACK_COMP_TURBOCELL 1 #define PACK_COMP_RADIODATA 2 #define PACK_COMP_GPS 3 #define PACK_COMP_LINKFRAME 4 #define PACK_COMP_80211FRAME 5 #define PACK_COMP_MANGLEFRAME 6 #define PACK_COMP_TRACKERNET 7 #define PACK_COMP_TRACKERCLIENT 8 #define PACK_COMP_KISCAPSRC 9 #define PACK_COMP_ALERT 10 #define PACK_COMP_BASICDATA 11 #define PACK_COMP_STRINGS 12 #define PACK_COMP_FCSBYTES 13 #define PACK_COMP_DEVICE 14 #define PACK_COMP_MAX 15 // Same game again, with alerts that internal things need to generate #define ALERT_REF_KISMET 0 #define ALERT_REF_MAX 1 // Define some macros (ew) to shortcut into the vectors we had to build for // fast access. Kids, don't try this at home. #define _PCM(x) globalreg->packetcomp_map[(x)] #define _NPM(x) globalreg->netproto_map[(x)] #define _ARM(x) globalreg->alertref_map[(x)] #define _ALERT(x, y, z, a) globalreg->alertracker->RaiseAlert((x), (y), \ (z)->bssid_mac, (z)->source_mac, (z)->dest_mac, (z)->other_mac, \ (z)->channel, (a)) // Send a msg via gloablreg msgbus #define _MSG(x, y) globalreg->messagebus->InjectMessage((x), (y)) // Record how a pid died struct pid_fail { pid_t pid; int status; }; // Record of how we failed critically. We want to spin a critfail message out // to the client so it can do something intelligent. A critical fail is something // like the root IPC process failing to load, or dropping dead. struct critical_fail { time_t fail_time; string fail_msg; }; // Global registry of references to tracker objects and preferences. This // should supplant the masses of globals and externs we'd otherwise need. // // Really this just just a big ugly hack to do globals without looking like // we're doing globals, but it's a lot nicer for maintenance at least. class GlobalRegistry { public: // argc and argv for modules to allow overrides int argc; char **argv; char **envp; // What are we? server, drone, client int kismet_instance; // getopt-long number for arguments that don't take a short letter // Anything using a getopt long should grab this and increment it int getopt_long_num; // Fatal terminate condition, as soon as we detect this in the main code we // should initiate a shutdown int fatal_condition; // Are we in "spindown" mode, where we're giving components a little time // to clean up their business with pollables and shut down int spindown; // Did we receive a SIGWINCH that hasn't been dealt with yet? bool winch; MessageBus *messagebus; Plugintracker *plugintracker; Packetsourcetracker *sourcetracker; // Old network tracker due to be removed Netracker *netracker; // New multiphy tracker Devicetracker *devicetracker; Packetchain *packetchain; Alertracker *alertracker; Timetracker *timetracker; KisNetFramework *kisnetserver; KisDroneFramework *kisdroneserver; ConfigFile *kismet_config; ConfigFile *kismetui_config; SoundControl *soundctl; KisBuiltinDissector *builtindissector; RootIPCRemote *rootipc; KisPanelInterface *panel_interface; Manuf *manufdb; string log_prefix; string version_major; string version_minor; string version_tiny; string revision; string revdate; // Vector of pollable subservices for main()... You should use the util // functions for this, but main needs to be able to see it directly vector<Pollable *> subsys_pollable_vec; // Vector of dumpfiles to close cleanly vector<Dumpfile *> subsys_dumpfile_vec; // Vector of child signals vector<pid_fail> sigchild_vec; time_t start_time; string servername; struct timeval timestamp; unsigned int metric; // Protocol references we don't want to keep looking up int netproto_map[PROTO_REF_MAX]; // Filter maps for the various filter types int filter_tracker; macmap<int> filter_tracker_bssid; macmap<int> filter_tracker_source; macmap<int> filter_tracker_dest; int filter_tracker_bssid_invert, filter_tracker_source_invert, filter_tracker_dest_invert; int filter_dump; macmap<int> filter_dump_bssid; macmap<int> filter_dump_source; macmap<int> filter_dump_dest; int filter_dump_bssid_invert, filter_dump_source_invert, filter_dump_dest_invert; int filter_export; macmap<int> filter_export_bssid; macmap<int> filter_export_source; macmap<int> filter_export_dest; int filter_export_bssid_invert, filter_export_source_invert, filter_export_dest_invert; mac_addr broadcast_mac; int alert_backlog; // Packet component references we use internally and don't want to keep looking up int packetcomp_map[PACK_COMP_MAX]; // Alert references int alertref_map[ALERT_REF_MAX]; unsigned int crc32_table[256]; Dumpfile_Pcap *pcapdump; // global netlink reference void *nlhandle; // Critical failure elements vector<critical_fail> critfail_vec; GlobalRegistry(); // External globals -- allow other things to tie structs to us int RegisterGlobal(string in_name); int FetchGlobalRef(string in_name); void *FetchGlobal(int in_ref); void *FetchGlobal(string in_name); int InsertGlobal(int in_ref, void *in_data); int InsertGlobal(string in_name, void *in_data); // Add something to the poll() main loop int RegisterPollableSubsys(Pollable *in_subcli); int RemovePollableSubsys(Pollable *in_subcli); // Add a log file void RegisterDumpFile(Dumpfile *in_dump); int RemoveDumpFile(Dumpfile *in_dump); Dumpfile *FindDumpFileType(string in_type); // Are we supposed to start checksumming packets? (ie multiple sources, // whatever other conditions we use) int checksum_packets; protected: // Exernal global references, string to intid map<string, int> ext_name_map; // External globals map<int, void *> ext_data_map; int next_ext_ref; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/kis_panel_widgets.h��������������������������������������������������������������0000664�0001750�0001750�00000064560�12124602454�017332� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KIS_PANEL_WIDGETS_H__ #define __KIS_PANEL_WIDGETS_H__ #include "config.h" // Panel has to be here to pass configure, so just test these #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES)) #ifdef HAVE_LIBCURSES #include <curses.h> #else #include <ncurses.h> #endif #include <panel.h> #undef erase #undef clear #undef move #include <stdio.h> #include <string> #include <vector> #include <list> #include "pollable.h" #include "messagebus.h" // Some standard filters we'd use on input #define FILTER_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "abcdefghijklmnopqrstuvwxyz" \ "0123456789" #define FILTER_NUM "0123456789" #define FILTER_ALPHANUM FILTER_ALPHA FILTER_NUM " " #define FILTER_ALPHANUMSYM FILTER_ALPHA FILTER_NUM \ " .,~!@#$%^&*()_-+/\\:=" class Kis_Panel; class KisPanelInterface; // Functor-style handler for special text. Provides an alternate to the // printstr mvwaddnstr which does color and type formating. // // Special string formatting: // \s .. \S - Standout // \u .. \U - Underline // \r .. \R - Reverse // \d .. \D - Dim // \b .. \B - Bold class Kis_Panel_Specialtext { public: static void Mvwaddnstr(WINDOW *win, int y, int x, string str, int n, Kis_Panel *panel, int colorpair = 0); static unsigned int Strlen(string str); }; class Kis_Panel_Color { public: Kis_Panel_Color(); int AddColor(string color, string pref); // Remap all instances using a color void RemapAllColors(string oldcolor, string newcolor, ConfigFile *conf); struct color_rec { string pref; string color[2]; int colorindex; }; protected: int nextindex; map<string, Kis_Panel_Color::color_rec> color_index_map; }; // Callback parameters - the component that activated, the status/return // code it activated with (retval from mouse/kb event) #define COMPONENT_CALLBACK_PARMS Kis_Panel_Component *component, int status, \ void *aux, GlobalRegistry *globalreg // Component is now active (most things won't need to use this since it ought // to be handled by the panel level key/mouse handlers #define COMPONENT_CBTYPE_SWITCH 0 // Component was activated - for whatever activated means for that widget. // Text fields would return activated on enter, buttons on click/enter, // etc. #define COMPONENT_CBTYPE_ACTIVATED 1 // Basic component super-class that handles drawing a group of items of // some sort class Kis_Panel_Component { public: Kis_Panel_Component() { fprintf(stderr, "FATAL OOPS: Component called without globalreg\n"); exit(1); } Kis_Panel_Component(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Panel_Component() { }; // Show/hide virtual void Show() { if (visible == 0) layout_dirty = 1; visible = 1; } virtual void Hide() { if (visible) layout_dirty = 1; visible = 0; } virtual int GetVisible() { return visible; } virtual void SetName(string in_name) { name = in_name; } virtual string GetName() { return name; } virtual void Debug() { fprintf(stderr, "debug - widget %p sx %d sy %d ex %d ey %d lx %d " "ly %d px %d py %d\n", this, sx, sy, ex, ey, lx, ly, px, py); } // Set the position inside a window (start x, y, and width, height) virtual void SetPosition(int isx, int isy, int iex, int iey) { sx = isx; sy = isy; ex = iex; ey = iey; lx = ex - sx; ly = ey - sy; layout_dirty = 1; } virtual void SetPreferredSize(int ipx, int ipy) { px = ipx; py = ipy; layout_dirty = 1; } virtual void SetMinSize(int imx, int imy) { mx = imx; my = imy; layout_dirty = 1; } virtual int GetMinX() { return mx; } virtual int GetMinY() { return my; } virtual int GetPrefX() { return px; } virtual int GetPrefY() { return py; } virtual int GetLayoutDirty() { return layout_dirty; } virtual void SetLayoutDirty(int d) { layout_dirty = d; } // Draw the component virtual void DrawComponent() = 0; // Activate the component (and target a specific sub-component if we have // some reason to, like a specific menu) virtual void Activate(int subcomponent) { active = 1; if (cb_switch != NULL) (*cb_switch)(this, 1, cb_switch_aux, globalreg); } // Deactivate the component (this could cause closing of a menu, for example) virtual void Deactivate() { active = 0; if (cb_switch != NULL) (*cb_switch)(this, 0, cb_switch_aux, globalreg); } // Handle a key press virtual int KeyPress(int in_key) = 0; // Handle a mouse event (default: Ignore) virtual int MouseEvent(MEVENT *mevent) { return 0; } virtual void SetCallback(int cbtype, int (*cb)(COMPONENT_CALLBACK_PARMS), void *aux); virtual void ClearCallback(int cbtype); virtual void SetColorPrefs(string in_active, string in_inactive) { color_active_pref = in_active; color_inactive_pref = in_inactive; } protected: // Silly function to pick the right color - give it the color you want, // and it gives you the inactive color if the widget is inactive inline int SetTransColor(int want_color) { if (active) { wattrset(window, want_color); return want_color; } else { wattrset(window, color_inactive); return color_inactive; } } GlobalRegistry *globalreg; // Primary colors int color_active; int color_inactive; string color_active_pref, color_inactive_pref; // Callbacks int (*cb_switch)(COMPONENT_CALLBACK_PARMS); void *cb_switch_aux; int (*cb_activate)(COMPONENT_CALLBACK_PARMS); void *cb_activate_aux; // Are we even visible? int visible; // Panel we're in Kis_Panel *parent_panel; // Widow we render to WINDOW *window; // Position within the window (start xy, size xy) int sx, sy, ex, ey, lx, ly, mx, my, px, py; int layout_dirty; // Are we active? int active; // Name string name; }; class Kis_Panel_Packbox : public Kis_Panel_Component { public: class packbox_details { public: Kis_Panel_Component *widget; int fill; int padding; }; Kis_Panel_Packbox() { fprintf(stderr, "FATAL OOPS: Kis_Panel_Packbox() called\n"); exit(1); } Kis_Panel_Packbox(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Panel_Packbox(); // Pack to head, end, before or after a named item, or remove from the pack list virtual void Pack_Start(Kis_Panel_Component *in_widget, int fill, int padding); virtual void Pack_End(Kis_Panel_Component *in_widget, int in_fill, int padding); virtual void Pack_Before_Named(string in_name, Kis_Panel_Component *in_widget, int fill, int padding); virtual void Pack_After_Named(string in_name, Kis_Panel_Component *in_widget, int fill, int padding); virtual void Pack_Remove(Kis_Panel_Component *in_widget); // Homogenous spacing (all elements fit in the same size) virtual void SetHomogenous(int in_homog) { homogenous = in_homog; layout_dirty = 1; } // Set the spacing between elements (but not trailing): WWWSWWW virtual void SetSpacing(int in_space) { spacing = in_space; layout_dirty = 1; } virtual void SetCenter(int in_cent) { center = in_cent; layout_dirty = 1; } // Are we packing vertical or horizontal? virtual void SetPackH() { packing = 0; layout_dirty = 1; } virtual void SetPackV() { packing = 1; layout_dirty = 1; } virtual int KeyPress(int in_key) { return -1; } virtual int GetVisible(); virtual void DrawComponent(); protected: list<Kis_Panel_Packbox::packbox_details> packed_items; virtual void Pack_Widgets(); int homogenous, packing, spacing, center; }; #define MENUITEM_CB_PARMS GlobalRegistry *globalreg, int menuitem, void *auxptr typedef void (*kis_menuitem_cb)(MENUITEM_CB_PARMS); class Kis_Menu : public Kis_Panel_Component { public: Kis_Menu() { fprintf(stderr, "FATAL OOPS: Kis_Menu called without globalreg\n"); exit(1); } Kis_Menu(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Menu(); // Refresh drawing the menu bar in its current state virtual void DrawComponent(); // Activate a specific menu (using the #*100+item scheme) virtual void Activate(int subcomponent); virtual void Deactivate(); // menu# * 100 + item# virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); // Add a menu & the hilighted character offset virtual int AddMenu(string in_text, int targ_char); // We can't delete, but we can hide a menu virtual void SetMenuVis(int in_menu, int in_vis); // Add an item to a menu ID virtual int AddMenuItem(string in_text, int menuid, char extra); // Add a submenu item to a menu ID, returns a menu we can add things // to for them to show up in the submenu virtual int AddSubMenuItem(string in_text, int menuid, char extra); // Set an item checkable virtual void SetMenuItemChecked(int in_item, int in_checked); // We can't delete, again, but we can hide virtual void SetMenuItemVis(int in_item, int in_vis); // Set a menu color virtual void SetMenuItemColor(int in_item, string in_color); // Set a menu item symbol (radio vs check vs ...) virtual void SetMenuItemCheckSymbol(int in_item, char in_symbol); // Set a menu item callback virtual void SetMenuItemCallback(int in_item, kis_menuitem_cb in_cb, void *in_aux); virtual void ClearMenuItemCallback(int in_item); virtual int FindMenu(string in_menu); // Delete all the menus virtual void ClearMenus(); virtual void EnableMenuItem(int in_item); virtual void DisableMenuItem(int in_item); virtual void EnableAllItems(int in_menu); virtual void DisableAllItems(int in_menu); struct _menuitem { int parentmenu; string text; char extrachar; int id; int enabled; int submenu; int visible; int checked; int colorpair; char checksymbol; kis_menuitem_cb callback; void *auxptr; }; struct _menu { string text; int targchar; vector<Kis_Menu::_menuitem *> items; int width; int id; int submenu; int visible; int checked; }; protected: // Menu helper window WINDOW *menuwin; WINDOW *submenuwin; // Menu bar vector<Kis_Menu::_menu *> menubar; // Selected items... When a sub menu is selected, the current menu gets put // into the sub menu record, and operations continue on the current menu. // Draw ops treat cur and sub as both "active" menus int cur_menu; int cur_item; int sub_menu; int sub_item; int mouse_triggered; int text_color, border_color, disable_color; virtual void FindNextEnabledItem(); virtual void FindPrevEnabledItem(); virtual void DrawMenu(_menu *menu, WINDOW *win, int hpos, int vpos); }; // TODO - fix this. Pop menus don't quite work right yet class Kis_Pop_Menu : public Kis_Menu { public: Kis_Pop_Menu() { fprintf(stderr, "FATAL OOPS: Kis_Pop_Menu called without globalreg\n"); exit(1); } Kis_Pop_Menu(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Pop_Menu(); virtual int KeyPress(int in_key); virtual void DrawComponent(); protected: virtual void DrawMenu(_menu *menu, WINDOW *win, int hpos, int vpos); }; // A scrollable list of fields class Kis_Field_List : public Kis_Panel_Component { public: Kis_Field_List() { fprintf(stderr, "FATAL OOPS: Kis_Field_List called without globalreg\n"); exit(1); } Kis_Field_List(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Field_List(); virtual void DrawComponent(); virtual int KeyPress(int in_key); // Add a row virtual int AddData(string in_field, string in_data); virtual int ModData(unsigned int in_row, string in_field, string in_data); protected: // Data vector<string> field_vec; vector<string> data_vec; // Width of field column and scrolling position unsigned int field_w; int scroll_pos; }; // A scrollable freetext field class Kis_Free_Text : public Kis_Panel_Component { public: Kis_Free_Text() { fprintf(stderr, "FATAL OOPS: Kis_Free_Text() called w/out globalreg\n"); exit(1); } Kis_Free_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Free_Text(); virtual void DrawComponent(); virtual int KeyPress(int in_key); virtual void SetText(string in_text); virtual void SetText(vector<string> in_text); virtual vector<string> GetText() { return text_vec; } virtual void AppendText(string in_text); virtual void SetMaxText(int in_max) { max_text = in_max; } // Follow the end of the text unless we're scrolled differently virtual void SetFollowTail(int in_set) { follow_tail = in_set; } virtual void SetAlignment(int in_alignment) { alignment = in_alignment; } protected: vector<string> text_vec; int scroll_pos; int alignment; int max_text; int follow_tail; }; class KisStatusText_Messageclient : public MessageClient { public: KisStatusText_Messageclient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { }; virtual ~KisStatusText_Messageclient() { } void ProcessMessage(string in_msg, int in_flags); }; // Status message field class Kis_Status_Text : public Kis_Panel_Component { public: Kis_Status_Text() { fprintf(stderr, "FATAL OOPS: Kis_Status_Text() called w/out globalreg\n"); exit(1); } Kis_Status_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Status_Text(); virtual void DrawComponent(); virtual int KeyPress(int in_key); virtual void AddLine(string in_line, int headeroffset = 0); protected: vector<string> text_vec; int scroll_pos; int status_color_normal; }; class Kis_Scrollable_Table : public Kis_Panel_Component { public: Kis_Scrollable_Table() { fprintf(stderr, "FATAL OOPS: Kis_Scrollable_Table called w/out globalreg\n"); exit(1); } Kis_Scrollable_Table(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Scrollable_Table(); virtual void DrawComponent(); virtual int KeyPress(int in_key); // Title format data struct title_data { int width; int draw_width; string title; int alignment; }; // Set the titles based on format data virtual int AddTitles(vector<Kis_Scrollable_Table::title_data> in_titles); // Add a row of data keyed to an int virtual int AddRow(int in_key, vector<string> in_fields); // Delete a keyed row virtual int DelRow(int in_key); // Replace a keyed row virtual int ReplaceRow(int in_key, vector<string> in_fields); // Get a rows data virtual vector<string> GetRow(int in_key); // Get the selected key virtual int GetSelected(); // Get the selected row data virtual vector<string> GetSelectedData(); // Set a selected row virtual int SetSelected(int in_key); // Clear all raws virtual void Clear(); // Highlight the selected row virtual void SetHighlightSelected(int in_set) { draw_highlight_selected = in_set; } // Lock scrolling to the top of the table, ie keep the bottom // visible all the time virtual void SetLockScrollTop(int in_set) { draw_lock_scroll_top = in_set; } virtual void SetDrawTitles(int in_set) { draw_titles = in_set; } struct row_data { int key; vector<string> data; }; protected: vector<title_data> title_vec; vector<row_data *> data_vec; map<int, int> key_map; int scroll_pos; int hscroll_pos; int selected; int draw_lock_scroll_top, draw_highlight_selected, draw_titles; }; enum KisWidget_LabelPos { LABEL_POS_NONE = -1, LABEL_POS_TOP = 0, LABEL_POS_LEFT = 1, LABEL_POS_BOT = 2, LABEL_POS_RIGHT = 3, LABEL_POS_BORDER = 4 }; // Single line input class Kis_Single_Input : public Kis_Panel_Component { public: Kis_Single_Input() { fprintf(stderr, "FATAL OOPS: Kis_Single_Input called w/out globalreg\n"); exit(1); } Kis_Single_Input(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Single_Input(); virtual void DrawComponent(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); // Allowed characters filter (mandatory) virtual void SetCharFilter(string in_charfilter); // Set the label and position virtual void SetLabel(string in_label, KisWidget_LabelPos in_pos); // Set the length of the text we want (can be more than the size of the // widget) (mandatory) virtual void SetTextLen(int in_len); // Pre-stock the widget text virtual void SetText(string in_text, int dpos, int ipos); // Get the text from the widget virtual string GetText(); protected: // Label, position (0 = top, 1 = left) string label; KisWidget_LabelPos label_pos; // Maximum length (may be more than the size of the widget) int max_len; // Characters we allow map<char, int> filter_map; /* text itself */ string text; /* Position of the start of the displayed text */ int curs_pos; /* Position of the input character */ int inp_pos; /* drawing length of the text field */ int draw_len; }; // A button class Kis_Button : public Kis_Panel_Component { public: Kis_Button() { fprintf(stderr, "FATAL OOPS: Kis_Button() called w/out globalreg\n"); exit(1); } Kis_Button(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Button(); virtual void DrawComponent(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetLabel(string in_text) { SetText(in_text); } virtual void SetText(string in_text); protected: string text; }; // A checkbox class Kis_Checkbox : public Kis_Panel_Component { public: Kis_Checkbox() { fprintf(stderr, "FATAL OOPS: Kis_Checkbox() called w/out globalreg\n"); exit(1); } Kis_Checkbox(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Checkbox(); virtual void DrawComponent(); virtual void Activate(int subcomponent); virtual void Deactivate(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetLabel(string in_text) { SetText(in_text); } virtual void SetText(string in_text); virtual int GetChecked(); virtual void SetChecked(int in_check); protected: string text; int checked; }; class Kis_Radiobutton : public Kis_Panel_Component { public: Kis_Radiobutton() { fprintf(stderr, "FATAL OOPS: Kis_Radiobutton() called w/out globalreg\n"); exit(1); } Kis_Radiobutton(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Radiobutton(); virtual void DrawComponent(); virtual void Activate(int subcomponent); virtual void Deactivate(); virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetText(string in_text); virtual int GetChecked(); virtual void SetChecked(int in_check); virtual void LinkRadiobutton(Kis_Radiobutton *in_button); protected: string text; int checked; vector<Kis_Radiobutton *> linked_vec; }; // Scaling interpolated graph class Kis_IntGraph : public Kis_Panel_Component { public: struct graph_label { string label; int position; // Used on markers int endposition; }; struct graph_source { int layer; string colorpref; string colordefault; int colorval; char line[2]; char fill[2]; vector<int> *data; string name; int overunder; }; Kis_IntGraph() { fprintf(stderr, "FATAL OOPS: Kis_IntGraph() called w/out globalreg\n"); exit(1); } Kis_IntGraph(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; graph_mode = 0; color_fw = 0; maxlabel = 0; xgraph_size = 0; label_x_graphref = -1; draw_scale = 1; draw_layers = 1; min_y = 0; max_y = 0; } virtual ~Kis_IntGraph() { }; virtual void DrawComponent(); virtual int KeyPress(int in_key); // Min/max values virtual void SetScale(int in_miny, int in_maxy) { min_y = in_miny; max_y = in_maxy; } // Interpolate graph to fit? virtual void SetInterpolation(int in_x) { inter_x = in_x; } virtual void SetXLabels(vector<graph_label> in_xl, string graphname) { label_x = in_xl; // Figure out which graph we reference label_x_graphref = -1; for (unsigned int x = 0; x < data_vec.size(); x++) { if (data_vec[x].name == graphname) { label_x_graphref = x; break; } } // Figure out the # of lines we need to save on the graph xgraph_size = 0; for (unsigned int x = 0; x < label_x.size(); x++) { if (xgraph_size < (int) label_x[x].label.size()) xgraph_size = (int) label_x[x].label.size() + 1; } } virtual void SetMode(int mode) { graph_mode = mode; } virtual void SetDrawScale(int in_draw_scale) { draw_scale = in_draw_scale; } virtual void SetDrawLayers(int in_draw_layers) { draw_layers = in_draw_layers; } // Add a data vector at a layer with a color preference, representation // character, over/under (1 over, 0 n/a, -1 under), and external vector. // All data sources must share a common min/max representation virtual void AddExtDataVec(string name, int layer, string colorpref, string colordefault, char line, char fill, int overunder, vector<int> *in_dv); protected: // Graph coordinates int min_y, max_y; // Interpolation int inter_x; int color_fw; // Graph mode // 0 = normal // 1 = over/under int graph_mode; int draw_scale, draw_layers; // Graph source vector vector<graph_source> data_vec; // Max label length unsigned int maxlabel; // Labels vector<graph_label> label_x; int xgraph_size, label_x_graphref; }; #if 0 // Polar graph class Kis_PolarGraph : public Kis_Panel_Component { public: struct graph_point { int id; string colorpref; string colordefault; int colorval; string name; double r, theta; }; Kis_PolarGraph() { fprintf(stderr, "FATAL OOPS: Kis_PolarGraph() called w/out globalreg\n"); exit(1); } Kis_PolarGraph(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) : Kis_Panel_Component(in_globalreg, in_panel) { globalreg = in_globalreg; active = 0; color_fw = 0; maxr = 0; } virtual ~Kis_PolarGraph() { }; virtual void DrawComponent(); virtual int KeyPress(int in_key); virtual void AddPoint(int id, graph_point gp); virtual void DelPoint(int id); virtual void ClearPoints(); protected: int color_fw; double maxr; vector<Kis_PolarGraph::graph_point> point_vec; }; // File picker widget, derivation of the scrollable table // Due to widget tabbing structure, can't easily nest multiple widgets into a // virtual packbox so directory changing has to be an external text box class Kis_Filepicker : public Kis_Scrollable_Table { public: Kis_Filepicker() { fprintf(stderr, "FATAL OOPS: Kis_Filepicker();\n"); exit(1); } Kis_Filepicker(GlobalRegistry *in_globalreg, Kis_Panel *in_panel); virtual ~Kis_Filepicker(); virtual void SetDirectory(string in_dir); virtual void SetFile(string in_file); virtual string GetDirectory() { return cur_directory; } virtual int KeyPress(int in_key); protected: string cur_directory, set_file; }; #endif class Kis_Panel { public: Kis_Panel() { fprintf(stderr, "FATAL OOPS: Kis_Panel() called w/out globalreg\n"); exit(1); } Kis_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *kpinterface); virtual ~Kis_Panel(); virtual void ShowPanel() { show_panel(pan); } virtual void Position(int in_sy, int in_sx, int in_y, int in_x); virtual int FetchSy() { return sy; } virtual int FetchSx() { return sx; } virtual int FetchSzy() { return sizey; } virtual int FetchSzx() { return sizex; } virtual int Poll(); virtual void ClearPanel() { wclear(win); } virtual void DrawPanel() { ColorFromPref(text_color, "panel_text_color"); ColorFromPref(border_color, "panel_border_color"); wbkgdset(win, text_color); werase(win); DrawTitleBorder(); DrawComponentVec(); wmove(win, 0, 0); } virtual int KeyPress(int in_key); virtual int MouseEvent(MEVENT *mevent); virtual void SetTitle(string in_title); virtual WINDOW *FetchDrawWindow() { return win; } virtual KisPanelInterface *FetchPanelInterface() { return kpinterface; } virtual Kis_Menu *FetchMenu() { return menu; } // Map a color pair out of preferences virtual void InitColorPref(string in_prefname, string in_def); virtual void ColorFromPref(int &clr, string in_prefname); virtual void RemapAllColors(string oldcolor, string newcolor); virtual int AddColor(string in_color); void AddComponentVec(Kis_Panel_Component *in_comp, int in_flags); void DelComponentVec(Kis_Panel_Component *in_comp); void SetActiveComponent(Kis_Panel_Component *in_comp); protected: // Bit values of what components expect to happen // COMP_DRAW - issue a draw command to this component during panel draw // components inside a packbox get called by the packbox and // don't need an explicit draw // COMP_TAB - Include in the list of components we tab to and activate, // gets an activate event and becomes the focus for keyboard // input // COMP_EVT - Generates events when triggered but may not necessarily be // tabable (menus gets COMP_EVT only) // COMP_STATIC Is not freed when the panel is destroyed, used for widgets // managed outside the panel itself #define KIS_PANEL_COMP_DRAW 1 #define KIS_PANEL_COMP_TAB 2 #define KIS_PANEL_COMP_EVT 4 #define KIS_PANEL_COMP_STATIC 8 struct component_entry { int comp_flags; Kis_Panel_Component *comp; }; void DrawComponentVec(); vector<component_entry> pan_comp_vec; GlobalRegistry *globalreg; KisPanelInterface *kpinterface; virtual void DrawTitleBorder(); WINDOW *win; PANEL *pan; string title; // Menus get treated specially because they have to be drawn last Kis_Menu *menu; int tab_pos; // Component which gets the keypress we didn't filter Kis_Panel_Component *active_component; int sx, sy, sizex, sizey; int text_color, border_color; // Main component sized to the full window (usually a packbox) Kis_Panel_Component *main_component; int last_key; struct timeval last_key_time; int escape_timer; }; // Pollable supersystem for handling panels and input class PanelInterface : public Pollable { public: PanelInterface(); PanelInterface(GlobalRegistry *in_globalreg); virtual ~PanelInterface(); virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); virtual int DrawInterface(); virtual void ResizeInterface(); virtual void AddPanel(Kis_Panel *in_panel); virtual void KillPanel(Kis_Panel *in_panel); protected: vector<Kis_Panel *> live_panels; int draweventid; vector<Kis_Panel *> dead_panels; int hsize, vsize; }; #endif // panel #endif // header ������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/dumpfile.h�����������������������������������������������������������������������0000664�0001750�0001750�00000003302�12124602454�015427� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_H__ #define __DUMPFILE_H__ #include "config.h" #include <stdio.h> #include <string> #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "filtercore.h" class Dumpfile { public: Dumpfile(); Dumpfile(GlobalRegistry *in_globalreg); virtual ~Dumpfile(); static void Usage(char *name); // Fetch the number of items logged int FetchNumDumped() { return dumped_frames; } // Fetch the name of the file being dumped to string FetchFileName() { return fname; } // Fetch the type of the file being dumped to string FetchFileType() { return type; } void SetVolatile(int in_volatile) { log_volatile = in_volatile; } // Cleanly flush the file to disk virtual int Flush() { return 0; }; protected: GlobalRegistry *globalreg; FilterCore *export_filter; string fname; string type; int dumped_frames; virtual string ProcessConfigOpt(string in_type); int resume; int log_volatile; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/kismet_json.cc�������������������������������������������������������������������0000664�0001750�0001750�00000035315�12124602454�016316� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "kismet_json.h" void JSON_delete(struct JSON_value *v) { for (unsigned int x = 0; x < v->value_array.size(); x++) { JSON_delete(v->value_array[x]); } for (map<string, struct JSON_value *>::iterator x = v->value_map.begin(); x != v->value_map.end(); ++x) { JSON_delete(x->second); } delete(v); } struct JSON_value *JSON_parse(string in_json, string& error) { vector<JSON_token> tok_vec; struct JSON_value *ret = NULL; JSON_token tk; JSON_token_type expected = JSON_unknown; int tk_st_escaped = 0; // Nested stack of values vector<struct JSON_value *> value_stack; vector<JSON_token *> symbol_stack; // Current block we're adding values to struct JSON_value *cur_val = NULL; // JSON token we're getting the symbol name from JSON_token *sym_tok = NULL; tk.tok_type = JSON_unknown; tk.tok_str = ""; tk.tok_position = 0; error = ""; // Step one, tokenize the input for (unsigned int x = 0; x < in_json.length(); x++) { if (tk_st_escaped > 0) tk_st_escaped--; if (in_json[x] == '\\' && !tk_st_escaped) { tk_st_escaped = 2; } // If we're in a quoted string, not exiting a quoted string, append if (tk.tok_type == JSON_quoted && !tk_st_escaped && in_json[x] != '"') { tk.tok_str += in_json[x]; continue; } // If we're in a number, we need to end on any separator; otherwise we'll // error later if (tk.tok_type == JSON_numeric) { switch (in_json[x]) { case ',': case '}': case ']': case ' ': // printf("DEBUG - end number '%s'\n", tk.tok_str.c_str()); tok_vec.push_back(tk); tk.tok_str = ""; tk.tok_type = JSON_unknown; break; } } if (in_json[x] == '"' && !tk_st_escaped) { // If we're unknown, this is a new quoted string if (tk.tok_type == JSON_unknown) { // printf("DEBUG - New quoted string\n"); tk.tok_type = JSON_quoted; tk.tok_position = x; continue; } // If we're known, we're ending this token if (tk.tok_type == JSON_quoted) { // printf("DEBUG - end quoted string '%s'\n", tk.tok_str.c_str()); tok_vec.push_back(tk); tk.tok_str = ""; tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == '{') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - {\n"); tk.tok_type = JSON_start; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == '}') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - }\n"); tk.tok_type = JSON_end; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == '[') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - [\n"); tk.tok_type = JSON_arrstart; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == ']') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - ]\n"); tk.tok_type = JSON_arrend; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == ' ') { continue; } if (in_json[x] == ':') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - :\n"); tk.tok_type = JSON_colon; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == ',') { if (tk.tok_type == JSON_unknown) { // printf("DEBUG - ,\n"); tk.tok_type = JSON_comma; tk.tok_position = x; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; continue; } } if (in_json[x] == '-') { if (tk.tok_type == JSON_unknown) { tk.tok_type = JSON_numeric; tk.tok_position = x; tk.tok_str += in_json[x]; continue; } } if (in_json[x] == '.') { if (tk.tok_type == JSON_numeric) { tk.tok_str += in_json[x]; continue; } } if (in_json[x] >= '0' && in_json[x] <= '9') { if (tk.tok_type == JSON_unknown || tk.tok_type == JSON_numeric) { if (tk.tok_type != JSON_numeric) tk.tok_position = x; tk.tok_type = JSON_numeric; tk.tok_str += in_json[x]; continue; } } if (in_json[x] == 't') { // Start looking for token 'true' if (in_json.substr(x, 4) == "true") { // printf("DEBUG - boolean TRUE\n"); tk.tok_type = JSON_boolean; tk.tok_position = x; tk.tok_str = "true"; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; tk.tok_str = ""; x += 3; continue; } } if (in_json[x] == 'f') { // Start looking for token 'true' if (in_json.substr(x, 5) == "false") { // printf("DEBUG - boolean FALSE\n"); tk.tok_type = JSON_boolean; tk.tok_position = x; tk.tok_str = "false"; tok_vec.push_back(tk); tk.tok_type = JSON_unknown; tk.tok_str = ""; x += 4; continue; } } // printf("DEBUG - Unexpected '%c'\n", in_json[x]); error = "Unexpected symbol '" + in_json.substr(x, 1) + "' at position " + IntToString(x); return ret; } // Parse the token stream expected = JSON_start; for (unsigned int x = 0; x < tok_vec.size(); x++) { // Debug - print it #if 0 switch (tok_vec[x].tok_type) { case JSON_unknown: printf("Unknown token\n"); break; case JSON_start: printf("START {\n"); break; case JSON_end: printf("END }\n"); break; case JSON_arrstart: printf("START [\n"); break; case JSON_arrend: printf("END ]\n"); break; case JSON_colon: printf("COLON :\n"); break; case JSON_comma: printf("COMMA ,\n"); break; case JSON_quoted: printf("STRING '%s'\n", tok_vec[x].tok_str.c_str()); break; case JSON_numeric: printf("NUMBER %s\n", tok_vec[x].tok_str.c_str()); break; case JSON_boolean: printf("BOOL %s\n", tok_vec[x].tok_str.c_str()); break; default: printf("oops\n"); break; } #endif // If we're in the initial state and we don't have anything... if (cur_val == NULL) { if (tok_vec[x].tok_type == JSON_start) { // printf("DEBUG - started initial dictionary\n"); ret = new struct JSON_value; cur_val = ret; // Flag that we're a dictionary cur_val->value.tok_type = JSON_start; // we expect a symbol expected = JSON_sym; continue; } } else if (expected == JSON_sym) { if (tok_vec[x].tok_type == JSON_quoted) { // printf("DEBUG - Got symbol %s\n", tok_vec[x].tok_str.c_str()); sym_tok = &(tok_vec[x]); // "foo":<value> expected = JSON_colon; continue; } } else if (expected == JSON_colon) { if (tok_vec[x].tok_type == JSON_colon) { expected = JSON_value; continue; } } else if (expected == JSON_value) { if (tok_vec[x].tok_type == JSON_quoted || tok_vec[x].tok_type == JSON_numeric || tok_vec[x].tok_type == JSON_boolean) { // printf("Debug - Got %s=>%s\n", sym_tok->tok_str.c_str(), tok_vec[x].tok_str.c_str()); // Make a value record for it struct JSON_value *v = new struct JSON_value; v->value = tok_vec[x]; // If we're in a dictionary, associate it if (cur_val->value.tok_type == JSON_start) { // printf(" Adding to dictionary\n"); cur_val->value_map[sym_tok->tok_str] = v; } else { // printf(" Adding to array\n"); cur_val->value_array.push_back(v); } // Expect some sort of separator, either end or comma expected = JSON_sep; continue; } else if (tok_vec[x].tok_type == JSON_start || tok_vec[x].tok_type == JSON_arrstart) { #if 0 if (tok_vec[x].tok_type == JSON_start) printf("DEBUG - starting new sub-dictionary\n"); else printf("DEBUG - starting new array\n"); #endif // Create a new container, of whatever type we're starting struct JSON_value *v = new struct JSON_value; v->value = tok_vec[x]; // printf("debug - descending to cur_val %p\n", v); // Push the current states onto the stack value_stack.push_back(cur_val); symbol_stack.push_back(sym_tok); // Insert it into a dictionary or append to an array based on our // current container type if (cur_val->value.tok_type == JSON_start) { // printf(" Nested under dictionary %s\n", sym_tok->tok_str.c_str()); cur_val->value_map[sym_tok->tok_str] = v; } else { // printf(" Adding to array\n"); cur_val->value_array.push_back(v); } // Set the next token if (tok_vec[x].tok_type == JSON_start) { // If we started a dictionary we need to wipe out the current // symbol, and expect a new one sym_tok = NULL; expected = JSON_sym; } else { // An array expects another value, symbol is irrelevant expected = JSON_value; } // Shift to the new container type cur_val = v; continue; } else if (tok_vec[x].tok_type == JSON_arrend || tok_vec[x].tok_type == JSON_end) { // If we're ending an array or dictionary, we pop off the current // value from the stack and reset, unless we're at the end of the // stack! if (cur_val == ret) { // printf("debug - end of starting block\n"); if (x != (tok_vec.size() - 1)) { // printf("debug - end of starting block before end of stream\n"); error = "JSON parser found end of JSON block before the " "end of the token stream at " + IntToString(tok_vec[x].tok_position); } // printf("debug - returning successfully!\n"); return ret; } else { // printf("DEBUG - end of array/dictionary, popping back\n"); // Pop back one in the stack cur_val = value_stack[value_stack.size() - 1]; value_stack.erase(value_stack.begin() + value_stack.size() - 1); sym_tok = symbol_stack[symbol_stack.size() - 1]; symbol_stack.erase(symbol_stack.begin() + symbol_stack.size() - 1); // printf("debug - popped bck to cur_val %p\n", cur_val); } // We retain the expectation of a separator... // printf("debug - ended block, expected %d\n", expected); expected = JSON_sep; continue; } } else if (expected == JSON_sep) { if (tok_vec[x].tok_type == JSON_comma) { if (cur_val->value.tok_type == JSON_start) { // If we're a dictionary we need a new symbol expected = JSON_sym; continue; } else { // We want another value expected = JSON_value; continue; } } else if (tok_vec[x].tok_type == JSON_arrend || tok_vec[x].tok_type == JSON_end) { // If we're ending an array or dictionary, we pop off the current // value from the stack and reset, unless we're at the end of the // stack! if (cur_val == ret) { // printf("debug - end of starting block\n"); if (x != (tok_vec.size() - 1)) { // printf("debug - end of starting block before end of stream\n"); error = "JSON parser found end of JSON block before the " "end of the token stream at " + IntToString(tok_vec[x].tok_position); } // printf("debug - returning successfully!\n"); return ret; } else { // printf("DEBUG - end of array/dictionary, popping back\n"); // Pop back one in the stack cur_val = value_stack[value_stack.size() - 1]; value_stack.erase(value_stack.begin() + value_stack.size() - 1); sym_tok = symbol_stack[symbol_stack.size() - 1]; symbol_stack.erase(symbol_stack.begin() + symbol_stack.size() - 1); // printf("debug - popped bck to cur_val %p\n", cur_val); } // We retain the expectation of a separator... // printf("debug - ended block, expected %d\n", expected); expected = JSON_sep; continue; } } // printf("debug - end of line, got %d wanted %d\n", tok_vec[x].tok_type, expected); error = "JSON parser got unexpected data at " + IntToString(tok_vec[x].tok_position); return ret; } return ret; } void JSON_dump(struct JSON_value *jsonv, string key, int depth) { string d; for (int x = 0; x < depth; x++) d += " "; // printf("%sValue type: %d\n", d.c_str(), jsonv->value.tok_type); if (jsonv->value.tok_type == JSON_start) { printf("%sDictionary\n", d.c_str()); for (map<string, struct JSON_value *>::iterator x = jsonv->value_map.begin(); x != jsonv->value_map.end(); ++x) { JSON_dump(x->second, x->first + string(" => "), depth + 1); } } else if (jsonv->value.tok_type == JSON_arrstart) { printf("%s%sArray\n", d.c_str(), key.c_str()); for (unsigned int x = 0; x < jsonv->value_array.size(); x++) { JSON_dump(jsonv->value_array[x], "", depth + 1); } } else if (jsonv->value.tok_type == JSON_quoted) { printf("%s%s'%s'\n", d.c_str(), key.c_str(), jsonv->value.tok_str.c_str()); } else if (jsonv->value.tok_type == JSON_numeric) { printf("%s%s%s\n", d.c_str(), key.c_str(), jsonv->value.tok_str.c_str()); } else if (jsonv->value.tok_type == JSON_boolean) { printf("%s%s%s\n", d.c_str(), key.c_str(), jsonv->value.tok_str.c_str()); } } struct JSON_value *JSON_dict_get_value(struct JSON_value *in_parent, string in_key, string& error) { map<string, struct JSON_value *>::iterator vitr; error = ""; if (in_parent == NULL) { error = "JSON dictionary parent doesn't exist"; return NULL; } if (in_parent->value.tok_type != JSON_start) { error = "JSON parent at " + IntToString(in_parent->value.tok_position) + " not a dictionary"; return NULL; } if ((vitr = in_parent->value_map.find(in_key)) == in_parent->value_map.end()) { error = "JSON no such key '" + in_key + "' in dictionary"; return NULL; } return vitr->second; } string JSON_dict_get_string(struct JSON_value *in_parent, string in_key, string& error) { struct JSON_value *v = JSON_dict_get_value(in_parent, in_key, error); error = ""; if (error.length() != 0) return ""; if (v == NULL) return ""; return v->value.tok_str; } float JSON_dict_get_number(struct JSON_value *in_parent, string in_key, string& error) { float f = 0.0f; string v = JSON_dict_get_string(in_parent, in_key, error); error = ""; if (error.length() != 0) return f; if (v == "true") return 1.0f; if (v == "false") return 0.0f; if (sscanf(v.c_str(), "%f", &f) != 1) { error = "JSON expected a numerical value but didn't get one"; return 0.0f; } return f; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/����������������������������������������������������������������0000775�0001750�0001750�00000000000�12124602454�016762� 5����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/Makefile��������������������������������������������������������0000664�0001750�0001750�00000002436�12124602454�020427� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC CLIOBJS = spectools_ui.o CLIOUT = spectools_ui.so SRVOBJS = spectool_netclient.o spectool_kismet.o SRVOUT = spectool_net.so all: $(SRVOUT) $(CLIOUT) $(CLIOUT): $(CLIOBJS) $(LD) $(PLUGINLDFLAGS) $(CLIOBJS) -o $(CLIOUT) $(LIBS) $(SRVOUT): $(SRVOBJS) $(LD) $(PLUGINLDFLAGS) $(SRVOBJS) -o $(SRVOUT) $(LIBS) install: $(SRVOUT) $(CLIOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $(SRVOUT) $(DESTDIR)/$(plugindir)/$(SRVOUT) mkdir -p $(DESTDIR)/$(plugindir)_client $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $(CLIOUT) $(DESTDIR)/$(plugindir)_client/$(CLIOUT) userinstall: $(SRVOUT) $(CLIOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) -v $(SRVOUT) ${HOME}/.kismet/plugins/$(SRVOUT) mkdir -p ${HOME}/.kismet/client_plugins/ $(INSTALL) -v $(CLIOUT) ${HOME}/.kismet/client_plugins/$(CLIOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/spectool_kismet.cc����������������������������������������������0000664�0001750�0001750�00000010040�12124602454�022470� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <config.h> #include <string> #include <errno.h> #include <time.h> #include <pthread.h> #include <sstream> #include <iomanip> #include <util.h> #include <messagebus.h> #include <packet.h> #include <packetchain.h> #include <packetsource.h> #include <packetsourcetracker.h> #include <timetracker.h> #include <configfile.h> #include <plugintracker.h> #include <globalregistry.h> #include <netracker.h> #include <packetdissectors.h> #include <dumpfile_pcap.h> #include <kis_ppi.h> #include <endian_magic.h> #include <version.h> #include "spectool_netclient.h" typedef struct { uint16_t pfh_datatype; uint16_t pfh_datalen; uint32_t start_khz; uint32_t res_hz; uint32_t amp_offset_mdbm; uint32_t amp_res_mdbm; uint16_t rssi_max; uint16_t num_samples; uint8_t data[0]; } ppi_spectrum; GlobalRegistry *globalreg = NULL; SpectoolsClient *stc = NULL; int pcm_specdata; int kisspec_dump(DUMPFILE_PPI_PARMS) { int ppi_pos; kis_spectrum_data *specdata = (kis_spectrum_data *) in_pack->fetch(pcm_specdata); if (specdata == NULL) { // Don't reset us to position 0 if data is missing and we've got a // position set to dump do (this means we're logging data, but not // in this packet!) if (dump_pos != 0) return dump_pos; return 0; } if (in_allocate) { return sizeof(ppi_spectrum) + specdata->rssi_vec.size(); } ppi_spectrum *ppi_spec; ppi_spec = (ppi_spectrum *) &(dump_data[dump_pos]); ppi_pos += sizeof(ppi_spectrum) + specdata->rssi_vec.size(); ppi_spec->pfh_datatype = kis_htole16(PPI_FIELD_SPECMAP); ppi_spec->pfh_datalen = kis_htole16(sizeof(ppi_spectrum) - sizeof(ppi_field_header) + specdata->rssi_vec.size()); ppi_spec->start_khz = kis_htole32(specdata->start_khz); ppi_spec->res_hz = kis_htole32(specdata->res_hz); ppi_spec->amp_offset_mdbm = kis_htole32(abs(specdata->amp_offset_mdbm)); ppi_spec->amp_res_mdbm = kis_htole32(specdata->amp_res_mdbm); ppi_spec->rssi_max = kis_htole16(specdata->rssi_max); ppi_spec->num_samples = kis_htole16(specdata->rssi_vec.size()); for (unsigned int s = 0; s < specdata->rssi_vec.size(); s++) ppi_spec->data[s] = specdata->rssi_vec[s]; return ppi_pos; } int kisspec_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->pcapdump == NULL || globalreg->packetchain == NULL || globalreg->kismet_config == NULL || globalreg->kisnetserver == NULL) return 0; stc = new SpectoolsClient(globalreg); pcm_specdata = stc->FetchPacketCompId(); globalreg->pcapdump->RegisterPPICallback(kisspec_dump, NULL); return 1; } int kisspec_unregister(GlobalRegistry *in_globalreg) { if (stc != NULL) delete stc; if (globalreg->pcapdump != NULL) globalreg->pcapdump->RemovePPICallback(kisspec_dump, NULL); } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "SPECTOOL"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "Spectool-Net"; data->pl_unloadable = 0; data->plugin_register = kisspec_register; data->plugin_unregister = kisspec_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/spectool_netclient.cc�������������������������������������������0000664�0001750�0001750�00000027016�12124602454�023174� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <sstream> #include <iomanip> #include "configfile.h" #include "clinetframework.h" #include "tcpclient.h" #include "kis_netframe.h" #include "packetchain.h" #include "spectool_netclient.h" #include "endian_magic.h" enum SPECTRUM_fields { SPEC_devname, SPEC_amp_offset_mdbm, SPEC_amp_res_mdbm, SPEC_rssi_max, SPEC_start_khz, SPEC_res_hz, SPEC_num_samples, SPEC_samples, SPEC_maxfield }; const char *SPECTRUM_fields_text[] = { "devname", "amp_offset_mdbm", "amp_res_mdbm", "rssi_max", "start_khz", "res_hz", "num_samples", "samples", NULL }; void Protocol_SPECTRUM_enable(PROTO_ENABLE_PARMS) { return; } int Protocol_SPECTRUM(PROTO_PARMS) { kis_spectrum_data *spec = (kis_spectrum_data *) data; ostringstream osstr; cache->Filled(field_vec->size()); for (unsigned int x = 0; x < field_vec->size(); x++) { unsigned int fnum = (*field_vec)[x]; if (fnum >= SPEC_maxfield) { out_string += "Unknown field requested"; return -1; } osstr.str(""); if (cache->Filled(fnum)) { out_string += cache->GetCache(fnum) + " "; continue; } switch (fnum) { case SPEC_devname: cache->Cache(fnum, "\001" + spec->dev_name + "\001"); break; case SPEC_amp_offset_mdbm: osstr << spec->amp_offset_mdbm; cache->Cache(fnum, osstr.str()); break; case SPEC_amp_res_mdbm: osstr << spec->amp_res_mdbm; cache->Cache(fnum, osstr.str()); break; case SPEC_rssi_max: osstr << spec->rssi_max; cache->Cache(fnum, osstr.str()); break; case SPEC_start_khz: osstr << spec->start_khz; cache->Cache(fnum, osstr.str()); break; case SPEC_res_hz: osstr << spec->res_hz; cache->Cache(fnum, osstr.str()); break; case SPEC_num_samples: osstr << spec->rssi_vec.size(); cache->Cache(fnum, osstr.str()); break; case SPEC_samples: for (unsigned int s = 0; s < spec->rssi_vec.size(); s++) { osstr << spec->rssi_vec[s]; if (s != spec->rssi_vec.size() - 1) osstr << ":"; } cache->Cache(fnum, osstr.str()); break; } out_string += cache->GetCache(fnum) + " "; } return 1; } int stc_recontimer(TIMEEVENT_PARMS) { ((SpectoolsClient *) parm)->Reconnect(); return 1; } void stc_connect_hook(GlobalRegistry *globalreg, int status, void *auxptr) { ((SpectoolsClient *) auxptr)->ConnectCB(status); } void SpectoolsClient::ConnectCB(int status) { if (status == 0) { _MSG("Using Spectools server on " + string(host) + ":" + IntToString(port), MSGFLAG_INFO); last_disconnect = 0; } else { _MSG("Could not connect to the spectools server " + string(host) + ":" + IntToString(port), MSGFLAG_ERROR); last_disconnect = globalreg->timestamp.tv_sec; } } SpectoolsClient::SpectoolsClient(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { globalreg = in_globalreg; tcpcli = new TcpClient(globalreg); netclient = tcpcli; RegisterNetworkClient(tcpcli); tcpcli->RegisterClientFramework(this); if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: Spectoolsclient called before packetchain\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Spectoolsclient called before kismet_config\n"); exit(1); } if (globalreg->kisnetserver == NULL) { fprintf(stderr, "FATAL OOPS: Spectoolsclient called before kisnetserver\n"); exit(1); } last_disconnect = 0; // Packetchain spectrum data packet_comp_id = globalreg->packetchain->RegisterPacketComponent("SPECTRUM"); // *SPECTRUM protocol spec_proto_id = globalreg->kisnetserver->RegisterProtocol("SPECTRUM", 0, 1, SPECTRUM_fields_text, &Protocol_SPECTRUM, &Protocol_SPECTRUM_enable, this); if (globalreg->kismet_config->FetchOpt("spectools") == "") { _MSG("No spectools= line in config file, will not try to use spectools " "for spectrum data", MSGFLAG_INFO); return; } char temphost[129]; if (sscanf(globalreg->kismet_config->FetchOpt("spectools").c_str(), "tcp://%128[^:]:%d", temphost, &port) != 2) { _MSG("Invalid spectools in config file, expected tcp://host:port, will " "not be able to use spectools", MSGFLAG_ERROR); return; } // Reconnect timer recon_timer_id = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC * 30, NULL, 1, &stc_recontimer, this); snprintf(host, MAXHOSTNAMELEN, "%s", temphost); tcpcli->Connect(host, port, stc_connect_hook, this); } SpectoolsClient::~SpectoolsClient() { if (recon_timer_id >= 0 && globalreg != NULL) globalreg->timetracker->RemoveTimer(recon_timer_id); globalreg->kisnetserver->RemoveProtocol(spec_proto_id); globalreg->RemovePollableSubsys(this); KillConnection(); } int SpectoolsClient::Shutdown() { if (tcpcli != NULL) { tcpcli->FlushRings(); tcpcli->KillConnection(); } return 1; } int SpectoolsClient::Reconnect() { if (tcpcli != NULL && tcpcli->Valid() == 0 && last_disconnect != 0) { tcpcli->KillConnection(); tcpcli->Connect(host, port, stc_connect_hook, this); } return 1; } int SpectoolsClient::ParseData() { int len, rlen; uint8_t *buf; int pos = 0; len = netclient->FetchReadLen(); if ((unsigned int) len < sizeof(wispy_fr_header)) return 0; buf = new uint8_t[len + 1]; if (netclient->ReadData(buf, len, &rlen) < 0) { _MSG("Failed to fetch spectool data from client connection", MSGFLAG_ERROR); KillConnection(); delete[] buf; return -1; } if ((unsigned int) rlen < wispy_fr_header_size()) { delete[] buf; return 0; } while ((rlen - pos) >= (int) wispy_fr_header_size()) { wispy_fr_header *whdr = (wispy_fr_header *) &(buf[pos]); if (kis_ntoh32(whdr->sentinel) != WISPY_NET_SENTINEL) { _MSG("Failed to find sentinel in spectool data stream, dropping " "connection", MSGFLAG_ERROR); KillConnection(); delete[] buf; return -1; } // Total sizeof frame including this header unsigned int wlen = kis_ntoh16(whdr->frame_len); // If we didn't peek a whole frame, go away if (rlen - (int) pos < (int) wlen) { delete[] buf; return 0; } netclient->MarkRead(wlen); pos += wlen; if (whdr->block_type == WISPY_NET_FRAME_DEVICE) { wispy_fr_device *dev; spectool_dev *localdev = NULL; for (unsigned int x = 0; x < whdr->num_blocks; x++) { if (wlen - wispy_fr_header_size() < wispy_fr_device_size() * (x + 1)) { delete[] buf; return -1; } dev = (wispy_fr_device *) &(whdr->data[wispy_fr_device_size() * x]); if (dev->device_version == WISPY_NET_DEVTYPE_LASTDEV) { state = spectool_net_state_configured; return 1; } for (unsigned int y = 0; y < device_vec.size(); y++) { if (device_vec[y]->dev_id == kis_ntoh32(dev->device_id)) { localdev = device_vec[x]; break; } } if (localdev == NULL) { localdev = new spectool_dev; device_vec.push_back(localdev); } localdev->dev_version = dev->device_version; localdev->dev_flags = kis_ntoh16(dev->device_flags); localdev->dev_id = kis_ntoh32(dev->device_id); localdev->dev_name = string((char *) dev->device_name, dev->device_name_len); localdev->amp_offset_mdbm = kis_ntoh32(dev->amp_offset_mdbm) * -1; localdev->amp_res_mdbm = kis_ntoh32(dev->amp_res_mdbm); localdev->rssi_max = kis_ntoh16(dev->rssi_max); localdev->start_khz = kis_ntoh32(dev->start_khz); localdev->res_hz = kis_ntoh32(dev->res_hz); localdev->num_samples = kis_ntoh16(dev->num_samples); // Enable it on the server wispy_fr_header *ehdr; wispy_fr_command *ecmd; wispy_fr_command_enabledev *edcmd; int sz = wispy_fr_header_size() + wispy_fr_command_size(wispy_fr_command_enabledev_size(0)); ehdr = (wispy_fr_header *) new uint8_t[sz]; ecmd = (wispy_fr_command *) ehdr->data; edcmd = (wispy_fr_command_enabledev *) ecmd->command_data; ehdr->sentinel = kis_hton32(WISPY_NET_SENTINEL); ehdr->frame_len = kis_hton16(sz); ehdr->proto_version = WISPY_NET_PROTO_VERSION; ehdr->block_type = WISPY_NET_FRAME_COMMAND; ehdr->num_blocks = 1; ecmd->frame_len = kis_hton16(wispy_fr_command_size(wispy_fr_command_enabledev_size(0))); ecmd->command_id = WISPY_NET_COMMAND_ENABLEDEV; ecmd->command_len = kis_hton16(wispy_fr_command_enabledev_size(0)); // Just use network endian source edcmd->device_id = dev->device_id; if (netclient->WriteData((void *) ehdr, sz) < 0) { delete[] ehdr; return -1; } delete[] ehdr; } } else if (whdr->block_type == WISPY_NET_FRAME_SWEEP) { wispy_fr_sweep *sweep; spectool_dev *localdev = NULL; unsigned int fr_pos = 0; for (unsigned int x = 0; x < whdr->num_blocks; x++) { // Make sure we can fit the frame header if (fr_pos >= (wlen - wispy_fr_sweep_size(0))) { _MSG("Invalid size for sweep record, disconnecting spectools " "client", MSGFLAG_ERROR); delete[] buf; return -1; } sweep = (wispy_fr_sweep *) &(whdr->data[fr_pos]); // Advance along the frame fr_pos += kis_ntoh16(sweep->frame_len); if (fr_pos >= wlen) { _MSG("Frame too short for sweep frame, disconnecting spectools " "client", MSGFLAG_ERROR); delete[] buf; return -1; } // Bail if we don't have a device for this for (unsigned int y = 0; y < device_vec.size(); y++) { if (device_vec[x]->dev_id == kis_ntoh32(sweep->device_id)) { localdev = device_vec[x]; break; } } if (localdev == NULL) { _MSG("Got spectool sweep frame for device we don't know about, " "skipping", MSGFLAG_ERROR); continue; } if (kis_ntoh16(sweep->frame_len) - wispy_fr_sweep_size(0) < localdev->num_samples) { _MSG("Got spectool sweep frame without the expected number " "of samples for device", MSGFLAG_ERROR); continue; } // Make a sweep record kis_spectrum_data *specdata = new kis_spectrum_data; specdata->dev_name = localdev->dev_name; specdata->start_khz = localdev->start_khz; specdata->res_hz = localdev->res_hz; specdata->amp_offset_mdbm = localdev->amp_offset_mdbm; specdata->amp_res_mdbm = localdev->amp_res_mdbm; specdata->rssi_max = localdev->rssi_max; specdata->start_tm.tv_sec = kis_ntoh32(sweep->start_sec); specdata->start_tm.tv_usec = kis_ntoh32(sweep->start_usec); for (unsigned int n = 0; n < localdev->num_samples; n++) { specdata->rssi_vec.push_back(sweep->sample_data[n]); } // Send it to everyone (before we add it to the packetchain which // frees it at the end) globalreg->kisnetserver->SendToAll(spec_proto_id, (void *) specdata); // Make a new packet in the chain kis_packet *newpack = globalreg->packetchain->GeneratePacket(); newpack->ts = specdata->start_tm; newpack->insert(packet_comp_id, specdata); globalreg->packetchain->ProcessPacket(newpack); } } } delete[] buf; return 1; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/spectool_netclient.h��������������������������������������������0000664�0001750�0001750�00000012220�12124602454�023025� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __SPECTOOLCLIENT_H__ #define __SPECTOOLCLIENT_H__ #include "config.h" #include "clinetframework.h" #include "tcpclient.h" #include "kis_netframe.h" #include "packetchain.h" #define WISPY_NET_FRAME_DEVICE 0x00 #define WISPY_NET_FRAME_SWEEP 0x01 #define WISPY_NET_FRAME_COMMAND 0x02 #define WISPY_NET_FRAME_MESSAGE 0x03 #define WISPY_NET_SENTINEL 0xDECAFBAD #define WISPY_NET_PROTO_VERSION 0x01 #define WISPY_NET_DEFAULT_PORT 30569 typedef struct _wispy_fr_header { uint32_t sentinel; uint16_t frame_len; uint8_t proto_version; uint8_t block_type; uint8_t num_blocks; uint8_t data[0]; } __attribute__ ((packed)) wispy_fr_header; /* Size of a container header */ #define wispy_fr_header_size() (sizeof(wispy_fr_header)) #define WISPY_NET_SWEEPTYPE_CUR 0x01 #define WISPY_NET_SWEEPTYPE_AVG 0x02 #define WISPY_NET_SWEEPTYPE_PEAK 0x03 typedef struct _wispy_fr_sweep { uint16_t frame_len; uint32_t device_id; uint8_t sweep_type; uint32_t start_sec; uint32_t start_usec; uint8_t sample_data[0]; } __attribute__ ((packed)) wispy_fr_sweep; /* Size of a sweep of N samples */ #define wispy_fr_sweep_size(x) (sizeof(wispy_fr_sweep) + (x)) #define WISPY_NET_DEVTYPE_USB1 0x01 #define WISPY_NET_DEVTYPE_USB2 0x02 #define WISPY_NET_DEVTYPE_LASTDEV 0xFF #define WISPY_NET_DEVFLAG_NONE 0x00 #define WISPY_NET_DEVFLAG_VARSWEEP 0x01 #define WISPY_NET_DEVFLAG_LOCKED 0x02 typedef struct _wispy_fr_device { uint16_t frame_len; uint8_t device_version; uint16_t device_flags; uint32_t device_id; uint8_t device_name_len; uint8_t device_name[256]; uint32_t amp_offset_mdbm; uint32_t amp_res_mdbm; uint16_t rssi_max; uint32_t def_start_khz; uint32_t def_res_hz; uint16_t def_num_samples; uint32_t start_khz; uint32_t res_hz; uint16_t num_samples; } __attribute__ ((packed)) wispy_fr_device; /* Size of a device frame of N sample definitions */ #define wispy_fr_device_size() (sizeof(wispy_fr_device)) #define WISPY_NET_TXTTYPE_INFO 0x00 #define WISPY_NET_TXTTYPE_ERROR 0x01 #define WISPY_NET_TXTTYPE_FATAL 0x02 typedef struct _wispy_fr_txtmessage { uint16_t frame_len; uint8_t message_type; uint16_t message_len; uint8_t message[0]; } __attribute__ ((packed)) wispy_fr_txtmessage; /* Size of a text message of N characters */ #define wispy_fr_txtmessage_size(x) (sizeof(wispy_fr_txtmessage) + (x)) #define WISPY_NET_COMMAND_NULL 0x00 #define WISPY_NET_COMMAND_ENABLEDEV 0x01 #define WISPY_NET_COMMAND_DISABLEDEV 0x02 #define WISPY_NET_COMMAND_SETSCAN 0x03 #define WISPY_NET_COMMAND_LOCK 0x04 #define WISPY_NET_COMMAND_UNLOCK 0x05 typedef struct _wispy_fr_command { uint16_t frame_len; uint8_t command_id; uint16_t command_len; uint8_t command_data[0]; } __attribute__ ((packed)) wispy_fr_command; #define wispy_fr_command_size(x) (sizeof(wispy_fr_command) + (x)) typedef struct _wispy_fr_command_enabledev { uint32_t device_id; } __attribute__ ((packed)) wispy_fr_command_enabledev; #define wispy_fr_command_enabledev_size(x) (sizeof(wispy_fr_command_enabledev)) typedef struct _wispy_fr_broadcast { uint32_t sentinel; uint8_t version; uint16_t server_port; } __attribute__ ((packed)) wispy_fr_broadcast; #define spectool_net_state_setup 0 #define spectool_net_state_configured 1 class SpectoolsClient : public ClientFramework { public: SpectoolsClient() { fprintf(stderr, "FATAL OOPS: spectoolsclient called without globalreg\n"); exit(1); } SpectoolsClient(GlobalRegistry *in_globalreg); virtual ~SpectoolsClient(); virtual int ParseData(); virtual int Shutdown(); struct spectool_dev { int dev_version; int dev_flags; unsigned int dev_id; string dev_name; int amp_offset_mdbm; int amp_res_mdbm; int rssi_max; int start_khz; int res_hz; unsigned int num_samples; }; virtual int Reconnect(); virtual int FetchPacketCompId() { return packet_comp_id; } virtual void ConnectCB(int status); protected: TcpClient *tcpcli; char host[MAXHOSTNAMELEN]; int port; int state; int recon_timer_id; int spec_proto_id; int packet_comp_id; int last_disconnect; vector<spectool_dev *> device_vec; }; class kis_spectrum_data : public packet_component { public: vector<int> rssi_vec; string dev_name; struct timeval start_tm; int start_khz; int res_hz; int amp_offset_mdbm; int amp_res_mdbm; int rssi_max; // dBm = (RSSI * (Amp_Res_mdBm / 1000)) + (Amp_Offset_mdBm / 1000) kis_spectrum_data() { self_destruct = 1; start_khz = 0; res_hz = 0; } ~kis_spectrum_data() { } }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/spectools_ui.cc�������������������������������������������������0000664�0001750�0001750�00000015440�12124602454�022005� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <config.h> #include <stdio.h> #include <string> #include <sstream> #include <globalregistry.h> #include <kis_panel_plugin.h> #include <kis_panel_frontend.h> #include <kis_panel_windows.h> #include <kis_panel_network.h> #include <kis_panel_widgets.h> #include <version.h> #define KCLI_SPECTRUM_CHANNEL_FIELDS "devname,amp_offset_mdbm,amp_res_mdbm," \ "start_khz,res_hz,samples" #define RSSI_CONVERT(O,R,D) (int) ((D) * ((double) (R) / 1000.0f) + \ ((double) (O) / 1000.0f)) void showspectrum_menu_callback(MENUITEM_CB_PARMS); struct spec_data { int mi_showspectrum; Kis_IntGraph *spectrum; vector<int> pack_cur, pack_avg, pack_peak; vector<Kis_IntGraph::graph_label> graph_label_vec; vector<vector<int> > avg_seed; int addref; string device; }; void SpecCliAdd(KPI_ADDCLI_CB_PARMS); extern "C" { int panel_plugin_init(GlobalRegistry *globalreg, KisPanelPluginData *pdata) { _MSG("Loading Kismet Spectools plugin", MSGFLAG_INFO); spec_data *adata; adata = new spec_data; pdata->pluginaux = (void *) adata; Kis_Menu *menu = pdata->kpinterface->FetchMainPanel()->FetchMenu(); int mn_view = menu->FindMenu("View"); pdata->kpinterface->FetchMainPanel()->AddViewSeparator(); adata->mi_showspectrum = menu->AddMenuItem("Spectrum", mn_view, 0); menu->SetMenuItemCallback(adata->mi_showspectrum, showspectrum_menu_callback, pdata); adata->spectrum = new Kis_IntGraph(globalreg, pdata->mainpanel); adata->spectrum->SetName("SPECTRUM"); adata->spectrum->SetPreferredSize(0, 12); adata->spectrum->SetScale(-120, -50); adata->spectrum->SetInterpolation(1); adata->spectrum->SetMode(0); adata->spectrum->AddExtDataVec("Current", 5, "spectrum_cur", "yellow,yellow", '#', '\0', 1, &(adata->pack_cur)); adata->spectrum->AddExtDataVec("Average", 4, "spectrum_avg", "green,green", ' ', ' ', 1, &(adata->pack_avg)); adata->spectrum->AddExtDataVec("Peak", 3, "spectrum_peak", "blue,blue", ' ', ' ', 1, &(adata->pack_peak)); pdata->mainpanel->AddComponentVec(adata->spectrum, KIS_PANEL_COMP_DRAW); string opt = pdata->kpinterface->prefs->FetchOpt("MAIN_SHOWSPECTRUM"); if (opt == "true" || opt == "") { adata->spectrum->Show(); pdata->mainpanel->SetPluginMenuItemChecked(adata->mi_showspectrum, 1); } else { adata->spectrum->Hide(); pdata->mainpanel->SetPluginMenuItemChecked(adata->mi_showspectrum, 0); } pdata->mainpanel->FetchNetBox()->Pack_After_Named("KIS_MAIN_NETLIST", adata->spectrum, 1, 0); adata->addref = pdata->kpinterface->Add_NetCli_AddCli_CB(SpecCliAdd, (void *) pdata); return 1; } void kis_revision_info(panel_plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } void SpecDetailsProtoSPECTRUM(CLIPROTO_CB_PARMS) { KisPanelPluginData *pdata = (KisPanelPluginData *) auxptr; spec_data *adata = (spec_data *) pdata->pluginaux; // "devname,amp_offset_mdbm,amp_res_mdbm,start_khz,res_hz,samples" if (proto_parsed->size() < 6) return; int fnum = 0; int amp_offset = 0, amp_res = 0, start_khz = 0, res_hz = 0; // Only process the first one we saw if (adata->device != "" && adata->device != (*proto_parsed)[fnum].word) return; adata->device = (*proto_parsed)[fnum++].word; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &_offset) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &_res) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &start_khz) != 1) return; if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &res_hz) != 1) return; vector<string> rssis = StrTokenize((*proto_parsed)[fnum++].word, ":"); adata->pack_cur.clear(); adata->pack_avg.clear(); adata->pack_peak.clear(); for (unsigned int x = 0; x < rssis.size(); x++) { int tint; int dbm; if (sscanf(rssis[x].c_str(), "%d", &tint) != 1) return; dbm = RSSI_CONVERT(amp_offset, amp_res, tint); adata->pack_cur.push_back(dbm); } adata->avg_seed.push_back(adata->pack_cur); if (adata->avg_seed.size() > 50) adata->avg_seed.erase(adata->avg_seed.begin()); for (unsigned int x = 0; x < adata->avg_seed.size(); x++) { for (unsigned int y = 0; y < adata->avg_seed[x].size(); y++) { // Add it to the totals if (y >= adata->pack_avg.size()) adata->pack_avg.push_back(adata->avg_seed[x][y]); else adata->pack_avg[y] += adata->avg_seed[x][y]; // Compare it to the peak if (y >= adata->pack_peak.size()) adata->pack_peak.push_back(adata->avg_seed[x][y]); else if (adata->pack_peak[y] < adata->avg_seed[x][y]) adata->pack_peak[y] = adata->avg_seed[x][y]; } } for (unsigned int x = 0; x < adata->pack_avg.size(); x++) { adata->pack_avg[x] = (int) ((float) adata->pack_avg[x] / adata->avg_seed.size()); } } void SpecCliConfigured(CLICONF_CB_PARMS) { KisPanelPluginData *pdata = (KisPanelPluginData *) auxptr; spec_data *adata = (spec_data *) pdata->pluginaux; if (recon) return; if (kcli->RegisterProtoHandler("SPECTRUM", KCLI_SPECTRUM_CHANNEL_FIELDS, SpecDetailsProtoSPECTRUM, pdata) < 0) { _MSG("Could not register SPECTRUM protocol with remote server", MSGFLAG_ERROR); } } void SpecCliAdd(KPI_ADDCLI_CB_PARMS) { KisPanelPluginData *pdata = (KisPanelPluginData *) auxptr; spec_data *adata = (spec_data *) pdata->pluginaux; if (add == 0) return; netcli->AddConfCallback(SpecCliConfigured, 1, pdata); } void showspectrum_menu_callback(MENUITEM_CB_PARMS) { KisPanelPluginData *pdata = (KisPanelPluginData *) auxptr; spec_data *adata = (spec_data *) pdata->pluginaux; string opt = pdata->kpinterface->prefs->FetchOpt("MAIN_SHOWSPECTRUM"); if (opt == "" || opt == "true") { pdata->kpinterface->prefs->SetOpt("MAIN_SHOWSPECTRUM", "false", 1); pdata->mainpanel->SetPluginMenuItemChecked(adata->mi_showspectrum, 0); adata->spectrum->Hide(); } else { pdata->kpinterface->prefs->SetOpt("MAIN_SHOWSPECTRUM", "true", 1); pdata->mainpanel->SetPluginMenuItemChecked(adata->mi_showspectrum, 1); adata->spectrum->Show(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-spectools/README����������������������������������������������������������0000664�0001750�0001750�00000004347�12124602454�017652� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Kismet-Spectools 1. What is Kismet-Spectools 2. Compiling 3. Installing 4. Using 1. What is Kismet-Spectools? Kismet-Spectools is a Kismet server and UI plugin which links to the Spectools spectrum analyzer network export (http://www.kismetwireless.net/spectools/), which lets Kismet display information about the wireless spectrum discovered by hardware such as the Wi-Spy (tm Metageek) 2. Compiling Compiling the Kismet-Spectools plugin requires the Kismet source be installed and configured on the system. By default, Kismet-Spectools expects the Kismet source to be in /usr/src/kismet, this can be overridden by setting the KIS_SRC_DIR environment variable or by symlinking this directory to your preferred build location. cd plugin-spectools KIS_SRC_DIR=/home/foo/src/kismet make 3. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet and /usr/local/lib/kismet_client) or in the users home directory (~/.kismet/plugins and ~/.kismet/client_plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-spectools KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-spectools make userinstall 4. Using Kismet-Spectools Once the plugins are installed, configure kismet_server to load plugins and to specify where spectools_net will be running by setting and adding the following to kismet.conf (by default in /usr/local/etc/): allowplugins=true spectools=tcp://localhost:30569 The spectools parameter should, obviously, be configured for whatever host you will use, if it is not running locally. Then load the Kismet UI plugin by starting Kismet and enabling it in "Kismet->Plugins->Select Plugins" The spectrum view can be shown or hidden via "Kismet->Plugins->Show Spectrum" If pcap logging is enabled, with the PPI logging format, Kismet will log PPI spectrum data once per second. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-syslog/�������������������������������������������������������������������0000775�0001750�0001750�00000000000�12124602454�016267� 5����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-syslog/Makefile�����������������������������������������������������������0000664�0001750�0001750�00000001553�12124602454�017733� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# You will need kismet newcore sources KIS_SRC_DIR ?= /usr/src/kismet KIS_INC_DIR ?= $(KIS_SRC_DIR) include $(KIS_SRC_DIR)/Makefile.inc BLDHOME = . top_builddir = $(BLDHOME) PLUGINLDFLAGS += -shared -rdynamic LIBS += -lstdc++ CFLAGS += -I$(KIS_INC_DIR) -g -fPIC CXXFLAGS += -I$(KIS_INC_DIR) -g -fPIC PLUGOBJS = kismet-syslog.o PLUGOUT = kismet-syslog.so all: $(PLUGOUT) $(PLUGOUT): $(PLUGOBJS) $(LD) $(PLUGINLDFLAGS) $(PLUGOBJS) -o $(PLUGOUT) $(LIBS) install: $(PLUGOUT) mkdir -p $(DESTDIR)/$(plugindir) $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 $^ $(DESTDIR)/$(plugindir)/$^ userinstall: $(PLUGOUT) mkdir -p ${HOME}/.kismet/plugins/ $(INSTALL) $(PLUGOUT) ${HOME}/.kismet/plugins/$(PLUGOUT) clean: @-rm -f *.o @-rm -f *.so .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o �����������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-syslog/kismet-syslog.cc���������������������������������������������������0000664�0001750�0001750�00000011424�12124602454�021412� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <config.h> #include <string> #include <errno.h> #include <time.h> #include <pthread.h> #include <sstream> #include <iomanip> #include <syslog.h> #include <util.h> #include <messagebus.h> #include <packet.h> #include <packetchain.h> #include <packetsource.h> #include <packetsourcetracker.h> #include <timetracker.h> #include <configfile.h> #include <plugintracker.h> #include <globalregistry.h> #include <devicetracker.h> #include <alertracker.h> #include <version.h> #include <gpscore.h> GlobalRegistry *globalreg = NULL; class SyslogMessageClient : public MessageClient { public: SyslogMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { watch_mask = 0; vector<string> mtoks = StrTokenize(StrLower(globalreg->kismet_config->FetchOpt("syslogtype")), ","); if (mtoks.size() == 0) { _MSG("Kismet-Syslog not redirecting any messages to syslog because no " "syslogtype= directive found in kismet.conf", MSGFLAG_ERROR); } string logtext = "no"; for (unsigned int x = 0; x < mtoks.size(); x++) { if (mtoks[x] == "no") { watch_mask = 0; break; } else if (mtoks[x] == "all") { watch_mask = MSGFLAG_ALL; logtext = "all"; break; } else if (mtoks[x] == "info") { watch_mask |= MSGFLAG_INFO; logtext = StringAppend(logtext, "info", ", "); } else if (mtoks[x] == "error") { logtext = StringAppend(logtext, "error", ", "); watch_mask |= MSGFLAG_ERROR; } else if (mtoks[x] == "alert") { logtext = StringAppend(logtext, "alert", ", "); watch_mask |= MSGFLAG_ALERT; } else if (mtoks[x] == "fatal") { watch_mask |= MSGFLAG_FATAL; logtext = StringAppend(logtext, "fatal", ", "); } } _MSG("Kismet-Syslog redirecting " + logtext + " messages to syslog", MSGFLAG_INFO); } virtual ~SyslogMessageClient() { } void ProcessMessage(string in_msg, int in_flags) { if ((in_flags & watch_mask) == 0) { return; } syslog(LOG_CRIT, "%s", in_msg.c_str()); } protected: int watch_mask; }; int alertsyslog_chain_hook(CHAINCALL_PARMS) { kis_alert_component *alrtinfo = NULL; if (in_pack->error) return 0; // Grab the alerts alrtinfo = (kis_alert_component *) in_pack->fetch(_PCM(PACK_COMP_ALERT)); if (alrtinfo == NULL) return 0; for (unsigned int x = 0; x < alrtinfo->alert_vec.size(); x++) { syslog(LOG_CRIT, "%s server-ts=%u bssid=%s source=%s dest=%s channel=%u %s", alrtinfo->alert_vec[x]->header.c_str(), (unsigned int) alrtinfo->alert_vec[x]->tm.tv_sec, alrtinfo->alert_vec[x]->bssid.Mac2String().c_str(), alrtinfo->alert_vec[x]->source.Mac2String().c_str(), alrtinfo->alert_vec[x]->dest.Mac2String().c_str(), alrtinfo->alert_vec[x]->channel, alrtinfo->alert_vec[x]->text.c_str()); } return 1; } int syslog_unregister(GlobalRegistry *in_globalreg) { return 0; } int syslog_register(GlobalRegistry *in_globalreg) { globalreg = in_globalreg; if (globalreg->kismet_instance != KISMET_INSTANCE_SERVER) { _MSG("Not initializing alertsyslog plugin, not running on a server.", MSGFLAG_INFO); return 1; } openlog(globalreg->servername.c_str(), LOG_NDELAY, LOG_USER); globalreg->packetchain->RegisterHandler(&alertsyslog_chain_hook, NULL, CHAINPOS_LOGGING, -100); SyslogMessageClient *sysm = new SyslogMessageClient(globalreg, NULL); globalreg->messagebus->RegisterClient(sysm, MSGFLAG_ALL); return 1; } extern "C" { int kis_plugin_info(plugin_usrdata *data) { data->pl_name = "SYSLOG"; data->pl_version = string(VERSION_MAJOR) + "-" + string(VERSION_MINOR) + "-" + string(VERSION_TINY); data->pl_description = "SYSLOG Plugin"; data->pl_unloadable = 0; // We can't be unloaded because we defined a source data->plugin_register = syslog_register; data->plugin_unregister = syslog_unregister; return 1; } void kis_revision_info(plugin_revision *prev) { if (prev->version_api_revision >= 1) { prev->version_api_revision = 1; prev->major = string(VERSION_MAJOR); prev->minor = string(VERSION_MINOR); prev->tiny = string(VERSION_TINY); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/plugin-syslog/README�������������������������������������������������������������0000664�0001750�0001750�00000003512�12124602454�017150� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Kismet-SYSLOG 1. What is Kismet-SYSLOG 2. Compiling 3. Installing 4. Using 1. What is Kismet-SYSLOG Kismet-SYSLOG is a Kismet plugin which provides a bridge from the Kismet alert and info system to standard unix syslog services. Alerts are logged as LOG_CRIT under the USER service. The syslog ID is the name assigned to the Kismet server. 2. Compiling Compiling the Kismet-SYSLOG plugin requires the Kismet source be installed and configured. By default, Kismet-SYSLOG expects the Kismet source to be in /usr/src/kismet; this can be overridden by setting the KIS_SRC_DIR environment variable: cd plugin-syslog/ KIS_SRC_DIR=/home/foo/src/kismet make 4. Installing Kismet plugins may be installed system-wide in the plugins directory (by default, /usr/local/lib/kismet/) or in the users home directory (~/.kismet/plugins) The default installation path can be overridden with the KIS_DEST_DIR variable if you have not installed Kismet in the default location and wish to install the plugin in the system-wide plugins directory: cd plugin-ptw KIS_DEST_DIR=/usr make install Plugins can be installed in the current users home directory with: cd plugin-ptw make userinstall 5. Using Once the plugin is loaded, Kismet will automatically log alerts to syslog. Messages from Kismet (the console output) can be logged by enabling the syslogtype=... line in kismet.conf Syslog log types can be: any All messages from Kismet are logged none No messages from Kismet are logged info INFO-class messages error ERROR-class messages fatal FATAL-class messages alert ALERT-class messages Examples: syslogtype=all syslogtype=error,fatal ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/getopt.h�������������������������������������������������������������������������0000664�0001750�0001750�00000010560�12124602454�015130� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This program 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 2, or (at your option) any later version. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #include "config.h" #ifdef __cplusplus extern "C" { #endif extern char *exec_name; /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if __STDC__ #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ /* extern int getopt (); */ #endif /* not __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ ������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/unixdomainserver.h���������������������������������������������������������������0000664�0001750�0001750�00000006427�12124602454�017237� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __UNIXDOMAINSERVER_H__ #define __UNIXDOMAINSERVER_H__ #include "config.h" #include <stdio.h> #include <string> #include <time.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/un.h> #include <unistd.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> #include <map> #include <vector> #include "ringbuf.h" #include "messagebus.h" #include "timetracker.h" #include "netframework.h" // Arbitrary 64k ring by default #define UNIX_SRV_RING_LEN (65536) /* man 7 unix */ #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif // WARNING: EXTREME CARE should be used if using this in an environment where // it is used on a suid-root kismet_server. Use with a suid-root kismet_capture // is perfectly safe, however this calls unlink() on potentially user-supplied // data which could allow an untrusted user to call it. // // Since kismet no longer uses suid-root on kismet_server, and does not load plugins // as root, this *should not* expose any avenues of attack not already available // (ie, running as root in the first place), but the warning remains. class UnixDomainServer : public NetworkServer { public: UnixDomainServer(); UnixDomainServer(GlobalRegistry *in_globalreg); virtual ~UnixDomainServer(); // Set up the Unix-domain socket and listening int SetupServer(const std::string& path, int mode, bool force, unsigned int in_maxcli); // Enable server virtual int EnableServer(); // Kill a connection by client ID virtual void KillConnection(int in_fd); // Fetch the info for a client id virtual int FetchClientConnectInfo(int in_clid, void *ret_info); // Shutdown the entire server virtual void Shutdown(); virtual string GetRemoteAddr(int in_fd); // Set the size of ring buffers. This ONLY affects new connections, not // existing! virtual void SetRingSize(int in_sz); protected: // Broker various acceptance stuff virtual int Accept(); // Validate a connection virtual int Validate(int in_fd); // Read pending bytes from the socket into the read ring buffer virtual int ReadBytes(int in_fd); // Write bytes from the write ring buffer to the socket virtual int WriteBytes(int in_fd); // Server info string socket_path; int socket_mode; /// File mode of the socket short int port; unsigned int maxcli; // Is it configured? int sv_configured; struct sockaddr_un serv_sock; // Ring length, if we resize it int int_ring_len; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/�����������������������������������������������������������������������������0000775�0001750�0001750�00000000000�12124602454�014226� 5����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/kismet.1���������������������������������������������������������������������0000664�0001750�0001750�00000007614�12124602454�015614� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.Dd April 2004 .Dt KISMET 1 .Os "Kismet" .Sh NAME .Nm kismet .Nd Wireless sniffing and monitoring .Sh SYNOPSIS .Ar kismet .Op server-options .Op Fl - .Op client-options .Pp .Ar kismet_server .Op Fl nqs .Op Fl t Ar title .Op Fl f Ar config-file .Op Fl c Ar capture-source .Op Fl C Ar enable-capture-sources .Op Fl l Ar log-types .Op Fl d Ar dump-type .Op Fl m Ar max-packets-per-file .Op Fl g Ar gpshost:port .Op Fl p Ar listen-port .Op Fl a Ar allowed-hosts .Op Fl N Ar server-name .Pp .Ar kismet_client .Op Fl qr .Op Fl f Ar config-file .Op Fl s Ar serverhost:port .Op Fl g Ar gui-type .Op Fl c Ar display-columns .Sh DESCRIPTION .Nm Kismet is an 802.11 layer2 wireless network detector, sniffer, and intrusion detection system. Kismet will work with any wireless card which supports raw monitoring (rfmon) mode, and can sniff 802.11b, 802.11a, and 802.11g traffic. Kismet identifies networks by passively collecting packets and detecting standard named networks, detecting (and given time, decloaking) hidden networks, and inferring the presence of nonbeaconing networks via data traffic. .br .Nm kismet supports logging to the wtapfile packet format (readable by tcpdump and ethereal) and saves detected network informat as plaintext, CSV, and XML. .Nm kismet is capable of using any GPS supported by .Nm gpsd and logs and plots network data. .Pp .Nm kismet is divided into three basic programs, .Nm kismet_server .Nm kismet_client and .Nm gpsmap .Sh USAGE .Nm kismet handles automatically starting kismet_server and kismet_client. .br .Nm kismet is installed as suid-root by default. It will drop privs to the user specified in .Nm kismet.conf immediately after binding and configuring the capture source. .Sh KISMET_SERVER .Nm kismet_server captures, dissects, and logs packets and GPS data. It is capable of running in `headless' mode with no display. Multiple clients (on multiple computers) can be connected to a single server. .Bl -tag -width flag .It Fl I Set the initial channel for a channel source (source:channel) .It Fl x Forcibly enable the channel hopper .It Fl X Forcibly disable the channel hopper .It Fl t Set the title used for the %t field of the logfile template (Default: Kismet) .It Fl n Disable all logging .It Fl f Use an alternate config file .It Fl c Override capture source lines (type,interface,name). Refer to kismet.conf(5) for more information. Multiple capture source options can be specified for multiple sources. All sources provided here are automatically enabled unless an enable list is also supplied. .It Fl C Comma-separated list to override what capture sources are enabled. .It Fl l Override logging types, comma separated (dump, cisco, weak, csv, xml, gps) .It Fl m Override maximum packets logged per file .It Fl q Override sound option and run in quiet mode .It Fl g Override GPS host:port .It Fl p Override port to listen on for clients .It Fl a Override list of client IPs or network/mask blocks (comma separated) allowed to connect .It Fl s Run in silent mode (no console status information) .It Fl N Override server name for this instance of Kismet .It Fl v Print version .It Fl h Help .El .Sh KISMET_CLIENT .Nm kismet_client is a ncurses and panels interface which connects to the server and displays detected networks, statistics, network details, etc. .Bl -tag -width flag .It Fl f Use an alternate config file .It Fl u Use an alternate UI config file .It Fl q Override sound option and run in quiet mode .It Fl s Override server host:port .It Fl r Attempt to automatically restablish the connection if the server terminates .It Fl g Override UI type (curses, panel) .It Fl c Override list of columns to display (comma seperated) .It Fl v Print version .It Fl h Help .El .Sh GPSMAP .Nm gpsmap reads GPS and Network XML datafiles and plots networks on downloaded maps or user-supplied images (such as satellite photos). .Sh SEE ALSO kismet_drone(1), gpsmap(1), kismet.conf(5), kismet_ui.conf(5), kismet_drone.conf(5) ��������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/gpsmap.1���������������������������������������������������������������������0000664�0001750�0001750�00000020526�12124602454�015604� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" Text automatically generated by txt2man-1.4.5 .TH gpsmap 1 "March 14, 2004" "" "" .SH NAME \fBgpsmap \fP- Wireless sniffing and monitoring \fB .SH SYNOPSIS .nf .fam C \fBgpsmap\fP [\fB-hviNIDVGMtbruapek\fP] [\fB-g\fP \fIconfig-file\fP] [\fB-o\fP \fIoutput-file\fP] [\fB-f\fP \fIfilter-list\fP] [\fB-F\fP \fIfilter-type-list\fP] [\fB-z\fP \fInumthreads\fP] [\fB-S\fP \fImapsource\fP] [\fB-c\fP \fIcoords\fP] [\fB-s\fP \fIscale\fP] [\fB-m\fP \fIusermap\fP] [\fB-d\fP \fImapsize\fP] [\fB-n\fP \fInetcolors\fP] [\fB-O\fP \fIoffset\fP] [\fIcolor-saturation\fP] [\fImap-intensity\fP] [\fB-R\fP \fIrange-opacity\fP] [\fIfeather-range\fP] [\fB-K\fP \fIbounds-opacity\fP] [\fB-U\fP \fIhull-opacity\fP] [\fB-A\fP \fIscatter-opacity\fP] [\fB-B\fP \fIscatter-size\fP] [\fBfeather-scatter\fP] [\fB-Z\fP \fIdraw-power-zoom\fI] [\fB-P\fP \fIpower-opacity\fP] [\fB-Q\fP \fIpower-res\fP] [\fB-q\fP \fIpower-colors\fP] [\fB-E\fP \fIcenter-opacity\fP] [\fB-H\fP \fIcenter-size\fP] [\fB-l\fP \fIlabel-list\fP] [\fB-L\fP \fIlabel-orientation\fP] [\fB-K\fP \fIlegend-opacity\fP] [\fB-F\fP \fIfeature-order\fP] .PP \fIGPSFile1\fP [\fIGpsFile2\fP \.\.\. \fIGpsFileN\fP] .fam T .fi .SH DESCRIPTION \fBgpsmap\fP reads GPS and Network XML datafiles and plots networks on downloaded vector maps or satellite photos or user-supplied images. .SH USAGE .TP .B \fB-h\fP, \fB--help\fP Display usage .TP .B \fB-v\fP, \fB--verbose\fP Verbose output .TP .B \fB-g\fP, --\fBconfig-file\fP FILE Use alternate config file FILE .TP .B \fB-o\fP, \fB--output\fP FILE Image output file .TP .B \fB-f\fP, \fB--filter\fP LIST Comma separated list of MACs to filter .TP .B \fB-i\fP, \fB--invert-filter\fP Process only MACs specified in the filter list .TP .B \fB-F\fP, \fB--typefilter\fP LIST Comma separated list of network types (ap,adhoc,probe,turbocell,data,unknown) to filter .TP .B \fB-I\fP, \fB--invert-typefilter\fP Process only MACs and types specified in the filter list .TP .B \fB-z\fP, \fB--threads\fP NUM Spawn NUM threads for power interpolation calculations .TP .B \fB-N\fP, \fB--pure-avg-center\fP Use old pure-average center to guess the center of a network by averaging all of the sample points, instead of the new code which tries to find the most relevant cluster of sample points. .TP .B \fB-S\fP, \fB--map-source\fP SOURCE Source to download maps from (-1 = Null; 0 = Mapblast; 1 = MapPoint(broken); 2 = Terraserver; 3 = Tiger Census; 4 = Earthamap; 5 = Terraserver Topographic). Default: 4 .TP .B \fB-D\fP, \fB--keep-gif\fP Keep downloaded GIF file .TP .B \fB-V\fP, \fB--version\fP Version of GPSMap .SH USAGE (IMAGE OPTIONS) .TP .B \fB-c\fP, --\fBcoords\fP LAT,LON Force map center to LAT,LON instead of automatically calculated location .TP .B \fB-s\fP, --\fBscale\fP SCALE Force map \fIscale\fP of SCALE instead of automatically calculated \fIscale\fP .TP .B \fB-m\fP, \fB--user-map\fP MAP Use custom map file instead of downloading one. If center and \fIscale\fP are specified in the map title they will be used. .TP .B \fB-d\fP, \fB--map-size\fP X,Y Download map at XSIZE,YSIZE. Default: 1280x1024 .TP .B \fB-n\fP, \fB--network-colors\fP COLORS Color networks by COLORS (0 = Random rotation; 1 = Color based on WEP and factory default; 2 = Color based on network channel). Default: 0 .TP .B \fB-G\fP, \fB--no-greyscale\fP Don't convert map to greyscale .TP .B \fB--color-saturation\fP PERCENTAGE Set background map image color saturation. 0 is greyscale, 100 is full normal colors. .TP .B \fB--map-intensity\fP [-]PERCENTAGE Set background map intensity. Negative percentages cause the map to be layered over a black background, while positive percentages cause the map to be layered over a white background. .TP .B \fB-M\fP, \fB--metric\fP Download map with metric measurements (if possible) .TP .B \fB-O\fP, --\fBoffset\fP XOFF,YOFF Offset map by XOFF,YOFF pixels. .SH USAGE (DRAWING OPTIONS) .TP .B \fB-t\fP, \fB--draw-track\fP Draw travel track .TP .B \fB-Y\fP, \fB--draw-track-width\fP WIDTH Travel track width. Default: 3 .TP .B \fB-b\fP, \fB--draw-bounds\fP Draw network bounding box .TP .B \fB-K\fP, \fB--draw-bounds-opacity\fP OPACITY Opacity to draw bounding boxes with. Default: 10 .TP .B \fB-r\fP, \fB--draw-range\fP Draw estimated range circles .TP .B \fB-R\fP, \fB--draw\fP-\fBrange-opacity\fP OPACITY Opacity to draw range circles with. Default: 70 .TP .B \fB--feather-range\fP Feather the range circles out into transparency .TP .B \fB-u\fP, \fB--draw-hull\fP Draw convex hull for each network .TP .B \fB-U\fP, \fB--draw\fP-\fBhull-opacity\fP OPACITY Opacity to draw convex hull with. Default: 70 .TP .B \fB-a\fP, \fB--draw-scatter\fP Draw scatter plot of data points .TP .B \fB-A\fP, \fB--draw\fP-\fBscatter-opacity\fP OPACITY Scatter plot opacity Default: 100 .TP .B \fB--feather-scatter\fP Feather the edges of scatterplot circles. VERY SLOW. .TP .B \fB-B\fP, \fB--draw\fP-\fBscatter-size\fP SIZE Draw scatter at radius size. Default: 2 .TP .B \fB-Z\fP, \fB--draw-power-zoom\fP Power based scatter plot range for scaling colors [Default: 0] 0 determines upper limit based on max observed for network 1-255 is user defined upper limit .TP .B \fB-p\fP, \fB--draw-power\fP Draw interpolated network power .TP .B \fB-P\fP, \fB--draw\fP-\fBpower-opacity\fP OPACITY Interpolated power opacity. Default: 70 .TP .B \fB-Q\fP, \fB--draw\fP-\fBpower-res\fP RES Interpolated power resolution. Default: 5 .TP .B \fB-q\fP, \fB--draw\fP-\fBpower-colors\fP COLORS Interpolated power color set. (0 is a ramp though RGB colorspace; 1 is the origional color set; 2 is weathermap radar style). Default: 0 .TP .B \fB-e\fP, \fB--draw-center\fP Draw dot at center of network range .TP .B \fB-E\fP, \fB--draw\fP-\fBcenter-opacity\fP OPACITY Center dot opacity. Default: 100 .TP .B \fB-H\fP, \fB--draw\fP-\fBcenter-size\fP SIZE Center dot at radius size. Default: 2 .TP .B \fB-l\fP, \fB--draw-labels\fP LIST Draw network label types, comma-seperated list. Labels are drawn in the order given. Valid labels are bssid, ssid, info, location, manuf. .TP .B \fB-L\fP, \fB--draw-label-orient\fP ORIENT Label orientation (0 upper left, 8 lower right) Default: 7 .TP .B \fB-k\fP, \fB--draw-legend\fP Draw map legend .TP .B \fB-K\fP, \fB--draw\fP-\fBlegend-opacity\fP OPACITY Legend opacity [Default: 90] .TP .B \fB-F\fP, --\fBfeature-order\fP ORDER String representing the order map features are drawn. (p: interpolated power; t: tracks; b: bounds; r: range circles; h: convex hulls; s: scatter plot; c: center dot; l: labels) Default: 'ptbrhscl'. .SH DRAWING METHODS .SS TRACK DRAWING Draws a blue track along the traveled path, based on the track data saved by Kismet. .SS BOUNDING RECTANGLE Draws the bounding rectangle around the extreme points of each network. .SS RANGE CIRCLE Estimates the range of a network based on the average center and the distance to the closest extreme corner. Not exact, but often useful for estimating the range of the network. .SS CONVEX HULL Convex hull of all sample points for each network. This will display the exact detected range of the networks. .SS SCATTER PLOT Draws a dot for every detected packet point. .SS POWER INTERPOLATION By far the most CPU intensive, power interpolation forms a grid over the image and attempts to interpolate the power for points that aren't directly sampled. For this graph to be a reasonable representation of reality, samples around the entire area, preferably forming a grid or mesh, should be taken. .SS NETWORK CENTER Simply draw a dot in the averaged center of each network .SS LABELS Labels are drawn in the order requested in the list. Labels are drawn based on the center of the network and the label orientation. There is some logic to attempt to prevent label overlap, but on extremely crowded maps it will be unavoidable. .SS LEGEND Draws a legend on the bottom of the map with the coordinates, scale, total sampled networks, networks visible on the current plot, and dynamic information based on the plots selected and the network color methods requested. .SH BUGS While not technically a bug, source 1 (MapPoint) are nonfunctional. The vendors have changed their serivice in such a way that it is impossible to download the map images from them. GPSMap still supports these sources, but ONLY for predownloaded images that may have been kept previously. Attempts to use these sources when a user map is not available will fail. .SH SEE ALSO \fBkismet\fP(1) .SH AUTHOR Mike Kershaw ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/kismet_drone.1���������������������������������������������������������������0000664�0001750�0001750�00000002565�12124602454�017003� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" Text automatically generated by txt2man-1.4.5 .TH kismet_drone 1 "February 24, 2002" "" "" .SH NAME \fBkismet_drone \fP- Wireless sniffing and monitoring remote drone \fB .SH SYNOPSIS .nf .fam C \fBkismet_drone\fP [\fB-svh\fP] [\fB-f\fP \fIconfig-file\fP] [\fB-c\fP \fIcapture-source\fP] [\fB-C\fP \fIenable-capture-sources\fP] [\fB-p\fP \fIport\fP] [\fB-a\fP \fIallowed-hosts\fP] [\fB-N\fP \fIserver-name\fP] .fam T .fi .SH DESCRIPTION \fBkismet_drone\fP supports all the capture sources available to Kismet. Instead of processing packets locally, kismet_drone makes them available via TCP to a remote kismet_server using the 'drone' capture source. .SH USAGE \fBkismet_drone\fP should be configured as you would \fBkismet_server\fP. All logging, packet dissection, etc will take place on the remote kismet server using the 'drone' capture source. .PP \fBkismet_monitor\fP should be used to place capture sources into rfmonitor mode as needed, and \fBkismet_hopper\fP should be used for channel hopping. .PP \fBkismet_drone\fP is controlled by the \fBkismet_drone.conf\fP config file. .SH ENCRYPTION It may be desireable to encrypt the packet stream between the remote drone and the kismet system. Standard SSH packet tunneling or any other tunneling/forwarding system may be used, and is recommended. .SH SEE ALSO \fBkismet\fP(1), \fBkismet_drone.conf\fP(5) .SH AUTHOR Mike Kershaw �������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/kismet.conf.5����������������������������������������������������������������0000664�0001750�0001750�00000001301�12124602454�016527� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH kismet.conf 5 "February 9, 2004" "" "" .SH NAME \fBkismet.conf \fP- Wireless sniffing and monitoring configuration file \fB .SH DESCRIPTION kismet expects a configuration file (/usr/local/etc/kismet.conf by default) which should conform to the following rules. A default configuration is provided with kismet but it is likely that you will need to modify it to suit your hardware and preferences. .SH CONFIGURATION FILE FORMAT All entries are of the format directive = value .SH MORE INFO The config file comments explain each option, and the README offers more information. .SH SEE ALSO \fBkismet_ui.conf\fP(5), \fBkismet_drone.conf\fP(5), \fBgpsmap\fP(1), \fBkismet\fP(1), \fBkismet_drone\fP(1) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/kismet_drone.conf.5����������������������������������������������������������0000664�0001750�0001750�00000003632�12124602454�017727� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" Text automatically generated by txt2man-1.4.5 .TH kismet_drone.conf 5 "Feb 24, 2003" "" "" .SH NAME \fBkismet_drone.conf \fP- Wireless sniffing and monitoring drone configuration file \fB .SH DESCRIPTION kismet_drone uses a minimalized configuration file, similar in options to the main kismet server configuration file. By default, the drone config is in /usr/local/etc/kismet.conf. A default configuration is included with Kismet but it is likely you will need to modify it to suit your hardware and preferences. .SH CONFIGURATION FILE FORMAT All entries are of the format directive = value .SH CONFIGURATION VALUES "include" (string) Include another config file. .PP "servername" (string) Name of this Kismet drone server. This is purely for information in multiple server systems. .PP "suiduser" (string) User to switch privileges to after binding to the capture. .PP "tcpport" (int) Port to serve streamed packet data .PP "allowedhosts" (string) Comma-separated list of IPs or network/mask pairs. Masks can be expressed as dotted quads (/255.255.255.0) or as numbers (/24) .PP "maxclient" (int) Maximum number of simultaneously connected clients .PP "source" (string) Comma-separated packet source (cardtype,interface,name). Multiple source lines can be defined, refer to the enablesources config line for more details. .PP .PP "enablesources" (string) Comma-separated list of source names (defined previously in the source lines) to enable. This is only needed if you wish to selectively enable multiple sources. For example: .RS enablesources=prism .PP enablesources=prism,cisco .RE .SH CARD TYPES AND MULTIPLE CAPTURE SOURCES kismet_drone supports the same sources and options as the core Kismet server. For details on supported capture types and how to define multiple capture sources, see kismet.conf(5). .SH SEE ALSO \fBkismet_drone\fP(1), \fBkismet.conf\fP(5), \fBkismet_ui.conf\fP(5), \fBgpsmap\fP(1), \fBkismet\fP(1) ������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/man/kismet_ui.conf.5�������������������������������������������������������������0000664�0001750�0001750�00000001124�12124602454�017227� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" Text automatically generated by txt2man-1.4.5 .TH kismet_ui.conf 5 "February 9, 2004" "" "" .SH NAME \fBkismet_ui.conf \fP- Wireless sniffing and monitoring configuration file \fB .SH DESCRIPTION The kismet_ui.conf file controls settings specific to the user interface. .SH CONFIGURATION FILE FORMAT All entries are of the format directive = value .SH MORE INFO The kismet_ui.conf file has comments explaining each config option, and the README contains more information. .SH SEE ALSO \fBkismet.conf\fP(5), \fBkismet_drone.conf\fP(5), \fBgpsmap\fP(1), \fBkismet\fP(1), \fBkismet_drone\fP(1) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/patches/�������������������������������������������������������������������������0000775�0001750�0001750�00000000000�12124602454�015102� 5����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/patches/README.patches�����������������������������������������������������������0000664�0001750�0001750�00000000722�12124602454�017411� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This directory includes patches for host systems which Kismet may need to perform properly (or at all) or to use more advanced features. linux-tuntapsetlink ------------------- This is a simple patch which applies to the Linux 2.6.x kernels and provides the ability to set the ARP link type on tun/tap virtual interfaces. Kismet uses this to set the link type of the tapX interface to wireless, so that other tools interpret the replicated packets properly. ����������������������������������������������kismet-2013-03-R1b/patches/linux-tuntapsetlink-r02-netdev.diff��������������������������������������0000664�0001750�0001750�00000003270�12124602454�023664� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[TUNTAP]: Allow setting the linktype of the tap device from userspace Currently tun/tap only supports the EN10MB ARP type. For use with wireless and other networking types it should be possible to set the ARP type via an ioctl. Patch v2: Included check that the tap interface is down before changing the link type out from underneath it Signed-off-by: Mike Kershaw <dragorn@kismetwireless.net> --- diff --git a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -18,6 +18,9 @@ /* * Changes: * + * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 + * Add TUNSETLINK ioctl to set the link encapsulation + * * Mark Smith <markzzzsmith@yahoo.com.au> * Use random_ether_addr() for tap MAC address. * @@ -612,6 +615,18 @@ static int tun_chr_ioctl(struct inode *i DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner); break; + case TUNSETLINK: + /* Only allow setting the type when the interface is down */ + if (tun->dev->flags & IFF_UP) { + DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", + tun->dev->name); + return -EBUSY; + } else { + tun->dev->type = (int) arg; + DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); + } + break; + #ifdef TUN_DEBUG case TUNSETDEBUG: tun->debug = arg; diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -77,6 +77,7 @@ struct tun_struct { #define TUNSETIFF _IOW('T', 202, int) #define TUNSETPERSIST _IOW('T', 203, int) #define TUNSETOWNER _IOW('T', 204, int) +#define TUNSETLINK _IOW('T', 205, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/README���������������������������������������������������������������������������0000664�0001750�0001750�00000225547�12124602454�014352� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Kismet 2013-03-R1 Mike Kershaw <dragorn@kismetwireless.net> http://www.kismetwireless.net 1. What is Kismet 2. Upgrading from earlier versions 3. Quick start 4. Suidroot & security 5. Capture sources 6. Caveats & quirks for specific drivers 7. Supported capture sources 8. Plugins 9. GPS 10. Logging 11. Filtering 12. Alerts & IDS 13. Server configuration options 14. Kismet UI 15. Kismet drones 16. Talking to Kismet 17. Troubleshooting 18. Frequently asked questions 1. What is Kismet Kismet is an 802.11 wireless network detector, sniffer, and intrusion detection system. Kismet will work with any wireless card which supports raw monitoring mode, and can sniff 802.11b, 802.11a, 802.11g, and 802.11n traffic (devices and drivers permitting). Kismet also sports a plugin architecture allowing for additional non-802.11 protocols to be decoded. Kismet identifies networks by passively collecting packets and detecting networks, which allows it to detect (and given time, expose the names of) hidden networks and the presence of non-beaconing networks via data traffic. 2a. Upgrading from recent versions 2009-06-R1 has changed some basic behavior when using multi-vap capable devices (ie, modern in-kernel Linux drivers). Whenever possible, it will create a new VAP and reconfigure it, instead of modifying the existing interface. To preserve the old behavior, specify 'forcevap=false' on the source line. 2b. Upgrading from Kismet-old versions This release marks a MAJOR change in how Kismet works and is configured. While many aspects are similar, many others (the client, configuring sources and channels, etc) are very different. To take advantage of the new features, replace your existing configuration files with the latest configuration data. Most notably: * Sources are defined differently. See the "Capture Sources" section. * All UI configuration is handled inside the Kismet client and stored in the users home directory in ~/.kismet/kismet_ui.conf * Most situations which were previously fatal conditions which caused Kismet to exit can now be recovered from. * New filtering options * New alert options * Completely new UI * Revamped network protocol * Significantly less CPU used for high numbers of networks * Plugins While this release breaks almost everything from previous releases, it opens the door for smoother upgrades and major feature enhancements. 3. Quick start PLEASE read the full manual, but for the impatient, here is the BARE MINIMUM needed to get Kismet working: * Download Kismet from http://www.kismetwireless.net/download.shtml * Run "./configure". Pay attention to the output! If Kismet cannot find all the headers and libraries it needs, major functionality may be missing. Most notably, compiling Kismet yourself will require the development packages and headers, usually called foo-dev or foo-devel. * Make sure that all the functionality you need was enabled properly in configure. Almost all users will need pcap and libnl support for proper operation. * Compile Kismet with "make". * Install Kismet with either "make install" or "make suidinstall". YOU MUST READ THE "SUID INSTALLATION & SECURITY" SECTION OF THE README OR YOUR SYSTEM MAY BE INSECURE. * If you have installed Kismet as suid-root, add your user to the "kismet" group * Run "kismet". If you did not install Kismet with suid-root support, you need to start it as root in nearly all situations. This is not recommended as it is less secure than privsep mode, where packet processing is segregated from admin rights. * When prompted to start the Kismet server, choose "Yes" * When prompted to add a capture interface, add your wireless interface. In nearly all cases, Kismet will autodetect the device type and supported channels. If it does not, you will have to manually define the capture type (as explained later in this README) * Logs will be stored in the directory you started Kismet from, unless changed via the "logprefix" config file or "--log-prefix" startup option. * READ THE REST OF THIS README. Kismet has a lot of features and a lot of configuration options, to get the most out of it you should read all of the documentation. 3b. Windows quick start * Note, at the time of this writing, the updated CACE install is not yet * available, so users wishing to take advantage of the newcore * functionality will need to build Kismet themselves in Cygwin Using the CACE Package: * Download the Win32/Cygwin installer created by CACE and linked from the download page (http://www.kismetwireless.net/download.shtml * Run the installer * Start Kismet * Pick your AirPcap or Kismet Drone sources * READ THE READ OF THIS README. Compiling it yourself: * Download the Cygwin setup tool (http://www.cygwin.org) * Install Cygwin with make, GCC, libncurses, libncurses-dev * Download the Airpcap_Devpack from CACE Support * Put Airpcap_Devpack and Libpcap_Devpack in the kismet source directory * Run "./configure", adding the options: --with-airpcap-devpack=... --with-winpcap-devpack=... --enable-airpcap The airpcap/winpcap devpack is available from the CACE website. Due to bugs in Cygwin, it appears that the airpcap and winpcap directories must be inside the kismet source directory. If they are not, the Kismet binary will immediately exit with no output. * Compile Kismet with "make". * Install Kismet with "make install" NOTE: KISMET WILL **ONLY** WORK WITH THE CACE AIRPCAP DEVICE, SAVED PCAP FILES, -OR- REMOTE KISMET DRONES RUNNING ON A SUPPORTED PLATFORM. NO OTHER HARDWARE IS SUPPORTED IN WINDOWS, PERIOD. WINDOWS DRIVERS DO NOT INCLUDE SUPPORT FOR WIFI MONITORING WHICH KISMET REQUIRES. THERE IS NO WAY TO CHANGE THIS. 3c. OSX/Darwin quick start * Please note: Many have complained that iTerm does not send correct key events. However, Terminal.app appears to work fine, and is recommended for using Kismet. * Download Kismet from http://www.kismetwireless.net/download.shtml * Run "./configure". Pay attention to the output! If Kismet cannot find all the headers and libraries it needs, major functionality may be missing. Notably, you may need to install libpcap manually. The libpcap included with OSX does not support PPI logging. Kismet will not be able to log to PPI correctly (so it will log 802.11 packets with no per-packet headers.) Configure will automatically detect OSX and default to the group "staff" for OSX suidinstall. This may be overridden with the '--with-suidgroup' configure option. * Compile Kismet with "make". * Install Kismet with either "make install" or "make suidinstall". YOU MUST READ THE "SUID INSTALLATION & SECURITY" SECTION OF THE README OR YOUR SYSTEM MAY BE VULNERABLE. * If you have installed Kismet as suid-root, add your user to the "staff" group if it is not already. * Run "kismet". If you did not install Kismet with suid-root support, you need to start it as root in nearly all situations. This is not recommended as it is less secure than privsep mode, where packet processing is segregated from admin rights. * When prompted to start the Kismet server, choose "Yes" * When prompted to add a capture interface, add your wireless interface. In nearly all cases, Kismet will autodetect the device type and supported channels. If it does not, you will have to manually define the capture type (as explained later in this README) For many Macs, this will be 'en1', however start a terminal and check the output of "ifconfig -a". The wireless interface must be enabled in the wireless control panel for Kismet to work, otherwise it will not find any networks. Kismet currently ONLY works with the Airport wireless devices, NOT USB WIRELESS DEVICES. * Logs will be stored in the directory you started Kismet from, unless changed via the "logprefix" config file or "--log-prefix" startup option. * READ THE REST OF THIS README 4. Suidroot & Security In order to configure the wireless card for monitor mode and start capturing packets, Kismet needs root access. There are two ways to accomplish this: Start Kismet as root, or install it so that the control components are set to start as root. Starting Kismet as root means that Kismet will continue running as root. In theory this presents no additional risk, however if there are any flaws in the Kismet packet dissection code then it may be possible for a malicious packet to cause code execution as root. Additionally, third-party plugins will run as root, and may not be secure. Installing Kismet as suid-root creates a limited-functionality binary (kismet_capture) which is only launchable by members of the "kismet" group. Kismet uses this to configure cards and control the channels, while packet decoding happens only in the user component, significantly limiting the attack surface. Distributions are strongly encouraged to use this method as it allows standard group controls for what users can use Kismet to change card states. Embedded systems typically have much less storage space and RAM, and often do not enforce user/root separation as strictly due to these limitations. On embedded systems, Kismet may be installed without the kismet_capture binary and run in root mode only, however the above risks still apply. Under no situation should the kismet_server binary itself be set suidroot as this will bypass any security checks. 5. Capture sources All packets in Kismet come from a capture source. Capture sources are typically network cards on the local system, however they can also be a previously recorded file or a remote capture system running a Kismet drone. Kismet will, in most cases, autodetect the driver and supported channels for a capture source given only the network interface. For many users this will be sufficient, however many expanded options are available for capture sources. Kismet captures packets at the 802.11 layer. This requires changing the mode of the network interface, making it unavailable for normal use. In most cases it is not possible to remain associated to a wireless network while running Kismet on the same interface. Capture sources may be added via the Kismet UI under the "Add Source" option, in which case the options may be added under the "Options:" field, comma separated. They may also be defined in the kismet.conf configuration file as the "ncsource=" option, such as: ncsource=wlan0:option1=foo,option2=bar Source options: name=foo Custom name for the source (otherwise it will be named the same as the capture interface). This is completely arbitrary and meaningful only to the user. type=foo Sources which can not autodetect the type must have the type specified. This is rarely necessary. Additional information on supported source types follows. uuid=foo Users wishing a static unique identifier on sources may specify one here. This is not necessary for most users. UUID is of the format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX hop=true|false Disable channel hopping on this source. Default behavior is for channel sources to hop channels to cover the entire spectrum. velocity=# Channel hop velocity (number of channels per second), Kismet can hop 1-10 channels per second. dwell=# Channel dwell time, the number of seconds Kismet will wait on each channel. If hopping is enabled and a channel dwell time is specified, Kismet will hop at N seconds per channel, instead of N channels per second. channellist=name Use an alternate channel list instead of the autodetected list of channels supported by this interface. The channellist must be defined. split=true|false When multiple sources use the same channel list (either autodetected or by the channellist= option) Kismet will split them so that they do not cover the same channels at the same time. Sources can be forced to ignore this and begin hopping at the beginning of the channel list regardless of overlap. retry=true|false Kismet will attempt to re-open a capture source which has encountered an error. This behavior can be disabled if the user wants the source to remain closed. vap=interface Create a secondary named interface for capture instead of trying to change the mode of the existing interface. This is primarily only for use by drivers using the mac80211 interface under Linux. Users wishing to do Kismet+Managed or Kismet+Injection should create a vap. forcevap=t|f True/False. Force creation of a monitor-mode VAP when possible (all Linux mac80211 based drivers support this). Default is "true", a VAP will be made of the name '<interface>mon', ie 'wlan0mon', 'wlan1mon' and capture will be done with this VAP. This behavior can be forced OFF with 'forcevap=false'. wpa_scan=time When using a mac80211 VAP, Kismet can use wpa_supplicant on a managed interface to trigger hardware assisted scans, enabling some view of the rest of the spectrum without significantly disrupting operation of the managed VAP. Suggested time for scan intervals is 15 seconds. validatefcs=t|f True/False. Kismet normally will not bother trying to validate the FCS checksum of incoming packets because most drivers only report valid frames in the first place. Packet sources which report invalid frames by default will enable this option automatically. If the drivers have been manually configured to report invalid packets, this should be specified to prevent Kismet from processing broken packets. fcs=true|false Force handling of FCS bytes on a packet source. Default is "false", which implies "native FCS handling". Packet sources which include per-packet headers like radiotap or PPI will ignore this value as the FCS is encoded in the radio header. Packet sources such as pcapfile, reading raw 802.11 pcap files with no headers, may need this turned on for proper behavior. fcsfail=true Force a mac80211 VAP to report packets with a known bad FCS (packet checksum). This is only available on Linux and only when using mac80211 drivers. This MUST come after a 'vap=' option or it will be ignored. Enabling 'fcsfail' will enable 'validatefcs' automatically. The 'fcsfail' option should only be enabled when logging to PPI; Logging to normal PCAP will not preserve the FCS data and will produce unreadable output. WARNING: With some driver versions, enabling this seems to cause kernel OOPS warnings and the interface will become unresponsive if capture is stopped and resume. This option is for specific expert use only, when in doubt, leave it alone. plcpfail=true Force a mac80211 VAP to report packets which do not pass the PLCP check (if possible on that interface). The same warnings and conditions as 'fcsfail' apply. This option is for specific, expert use only, when in doubt, leave it alone. ignoreprimary=t Ignore the state of the primary interface on mac80211. Normally, Kismet will shut down the main interface (ie wlan0, wlan1) to prevent wpasupp or NetworkManager from changing the channel, etc. Example sources (these are given as config file parameters, however they will work equally well as command-line options, ie "-c wlan0"): Capture on wlan0, channel 6, don't channel hop ncsource=wlan0:hop=false,channel=6 Capture on wlan0, 802.11b channels only even if it supports 5GHz ncsource=wlan0:channellist=IEEE80211b Create a VAP on wlan0 named wlan0mon and use wpa_supplicant to give us some view of other channels, while remaining associated to a network: ncsource=wlan0:vap=wlan0mon,hop=false,wpa_scan=15 Read from a pre-recorded pcap file: ncsource=/home/foo/old.pcap Capture using the first Airpcap device on Windows ncsource=airpcap Capture using a remote capture drone ncsource=drone:host=10.10.100.2,port=2502 Channel lists: Channel lists control the channels and patterns hopped to by capture sources in Kismet, when the channels can not be autodetected (or when the user wishes to override them for some reason). The default channel lists (IEEE80211b, IEEE80211a, and IEEE80211ab) are used only when a channel list is not provided by the driver, so should not be changed in most cases. When the channel list is automatically created from the channels supported by the driver, the preferredchannels= option will control which channels are weighted for extra time. By setting this to channels known to be defaults (such as 1, 6, 11) or channels with known networks of interest (such as in a stationary install), Kismet will devote more time to those channels to gather more information. For more complex channel timing, keep reading about how channel lists work. Channels can typically be specified as IEEE channels (11, 36, etc) or as frequencies (2401, 5200) however some platforms and drivers may not support specifying channels or frequencies out of the IEEE standard range. channellist=name:channel,channel,channel Additionally, individual channels in the list can be weighted so that more time is spent on them; for a weighting value of 3, 3x more time is spent on that channel. channellist=foo:1:3,6:3,11:3,2,3,4,5,6,7,8,9,10 Up to 256 channels may be specified in a channel list. For greater numbers of channels, a range must be specified. Ranges may consist of channels or of frequencies. channellist=name:range-[start]-[end]-[overlap]-[iteration] Channels between start and end, at a given iteration. Kismet will not hop directly between channels that overlap. channellist=foo:range-1-11-3-1 A similar range using frequencies (802.11 2.4GHz channels are ~20MHz wide; technically 22 but 20 suffices, and 5 MHz apart). channellist=foo:range-2412-2462-20-5 Ranges are NOT split between sources. Multiple sources hopping on the same channel list which includes a range will not split the expanded range - in other words, channel ranges are treated as a single channel entry. Multiple ranges can be specified in a single channel list, separated by commas. They may also be mixed with channels: channellist=foo:range-1-11-3-1,36,52 6. Caveats and quirks for specific drivers: Mac80211 General (Linux): At the time of this release, the mac80211 drivers in Linux are undergoing significant development, which means at any given time they can exhibit extremely odd behavior or be outright broken. Users are encouraged to upgrade to the latest kernel, and to consider installing the compat-wireless backport package, if problems are experienced. Madwifi (Linux): Madwifi-ng has been largely deprecated by ath5k/ath9k for normal usage. These drivers support multi-vap more cleanly via the mac80211 layer and do not, typically, have the same problems historically present in madwifi. Madwifi-ng sources can be specified as either the VAP (ath0, mon0, etc) or as the control interface (wifi0, wifi1). However, IF THE CONTROL INTERFACE IS SPECIFIED, Kismet cannot extract the list of supported channels, and will default to IEEE80211b channels. Madwifi-ng continues to have problems with multi-vap and initial vap creation. It is recommended that the initial VAP creation be turned off by the module parameter "autocreate=none" when loading ath_pci. If the madwifi monitor vap stops reporting packets soon after being created, this is often the cause. Combining managed and monitor VAPs appears to still not work well. RT28xx (Linux) There are 2 drivers for the RT28xx chipsets. The in-kernel driver available as of Linux-2.6.31 works properly with Kismet. This is by far the preferred driver to use. Be sure to enable the RT28xx driver in the wireless drivers section, NOT the staging driver. The staging driver is not mac80211 based and will not necessarily behave. The out-of-kernel driver does not conform to mac80211 controls. This driver also cannot be auto-detected (they don't provide a valid identifier in /sys) so the driver type mus be manually specified with 'type=rt2870sta' on the source line. This driver defaults to the name 'rausbX' which exposes a bug in some versions of libpcap and may require the device be renamed (See 'Troubleshooting' section) rt73-k2wrlz (Linux) An out-of-tree rt73 driver similar to rt2870sta. It may be necessary to specify a type of 'rt73' manually when using this driver. This driver defaults to the name 'rausbX' which exposes a bug in some versions of libpcap and may require the device be renamed (See 'Troubleshooting' section) WL (Linux, Intel) Broadcom has released a binary version of their drivers called WL. These drivers are incapable of monitor mode, and cannot be used with Kismet. Kismet will attempt to autodetect them and report this to the user. Users of Broadcom cards should use the b43 or b43xx in-kernel drivers. OTUS (Linux) Atheros released a driver for the 802.11n USB devices; however, this does not have support for monitor mode and cannot be used with Kismet. The ar9170 driver project is providing mac80211 kernel support for this card, and works with Kismet. ar9170 has been merged with the wireless-git development kernel and should be present in the compat-wireless packages. Nokia ITT (Linux) For any chance of Kismet working on the Nokia ITT, the scan interval must be set to zero in the Nokia system control panel, connectivity section. It should be disconnected from any network, but wireless must be turned on. The Nokia drivers often return FCS-invalid packets. The Nokia source line should include 'fcs=true,validatefcs=true' to prevent these from creating multiple false networks out of invalid packets. The Nokia device does not autodetect properly, a driver type of 'nokia770', 'nokia800', 'nokia810', or 'nokiaitt' must be set. 'nokiaitt' is a generic source which should work on any Nokia ITT tablet. Orinoco (Linux) Due to problems in monitor mode with newer firmwares, the Orinoco kernel drivers have disabled monitor mode for newer/"modern" firmware versions in the Orinoco cards. Kismet will attempt to use the device, but warn the user that it will probably fail. Monitor support can be forced on in the module via the module parameter "force_monitor=1" when loading orinoco.ko. For non-hermes chipsets like prism2, use hostap (also in the kernel). NDISWrapper (Linux) The NDIS-Wrapper driver loads Windows drivers into the Linux network stack. These drivers are not capable of monitor mode, and will not work with Kismet. Note: The rndis drivers are NOT the same as ndiswrapper. rndis drivers are for a specific USB chipset and are not related to ndiswrapper, rndis will work. BSD (BSD Generic) Cards which work under the generic BSD framework for monitor mode with radiotap headers should work with Kismet via the source types "radiotap_bsd_ag", "radiotap_bsd_a", "radiotap_bsd_g", and "radiotap_bsd". Channel detection and device type autodetection are currently not supported. ncsource=wl0:type=radiotap_bsd_ag Windows (Generic) ONLY THE AIRPCAP DEVICE IS SUPPORTED UNDER WINDOWS. THIS IS A SPECIFIC HARDWARE DEVICE MADE BY CACE TECHNOLOGIES. IF YOU DID NOT GO AND BUY AN AIRPCAP SPECIFICALLY FOR CAPTURING DATA, YOU DO NOT HAVE ONE, AND THIS WILL NOT WORK. The Airpcap has monitor mode drivers with a *public* interface for controlling them. This is the only device Kismet can capture packets from on Windows. AirPcap (Windows) By default Kismet will open the first Airpcap device found. Multiple devices can be opened by using the full named interface, which can be found in the AirPcap tools but follows the pattern \\.\airpcapXX ; The first device is \\.\airpcap00, the second is \\.\airpcap01, and so on. USB Devices (OSX) Only devices using the Airport IOKit drivers are supported on OSX. USB devices are, in general, not supported because the drivers lack monitor mode or a method to set the channel. 7. Supported capture source types Capture source types are only required in specific situations where Kismet cannot detect the capture source type automatically. Linux Capture Sources: All modern drivers on Linux use the mac80211 driver framework. Kismet will auto-detect any driver using this framework. A generic source type 'mac80211' can be used for forcing a type, however it is not strictly useful to do so. adm8211 Kernel adm8211 driver acx100 Kernel acx100 driver hostap Kernel prism2 driver ipw2100 Kernel Intel 2100 driver ipw2200 Kernel Intel 2200 driver ipw2915 Kernel Intel 2915 driver ipw3945 Kernel intel 3945 driver mac80211 Generic mac80211 catch-all source for any mac80211 drivers. madwifi Madwifi/Madwifi-ng madwifi_a Alias for madwifi, default 802.11a channels madwifi_b Alias for madwifi, default 802.11b/g channels madwifi_g Alias for madwifi, default 802.11b/g channels madwifi_ag Alias for madwifi, default 802.11abg channels nokia770 Conexant-based driver in Nokia Maemo tablets nokia800 Alias for nokia770 nokia810 Alias for nokia770 nokiaitt Alias for nokia770 pcapfile Pcap-formatted previously recorded file rt2870sta Out-of-kernel/Staging rt2870 11n driver (use in-kernel instead) wl12xx Patched wl12xx drivers for the N900, must use patched drivers from http://david.gnedt.eu/blog/, otherwise autodetected. drone Remote Kismet packet capture, source options "host=..." and "port=..." are required. ncsource=drone:host=localhost,port=2502 BSD Capture Sources: Currently, the BSD packet capture sources do not support autodetection or channel detection. Capture on BSD should work with any driver which supports monitor mode and which uses the standard BSD IOCTLs to set the mode and channel. Patches/Additional BSD support welcome. radiotap_bsd Generic BSD capture source, default 802.11b/g channels radiotap_bsd_g Default 802.11b/g channels radiotap_bsd_a Default 802.11a channels radiotap_bsd_ag Default 802.11abg channels pcapfile Pcap-formatted previously recorded file drone Remote Kismet packet capture, source options "host=..." and "port=..." are required. Windows Capture Sources: Currently ONLY THE AIRPCAP DEVICE, PCAP FILE, AND DRONES RUNNING ON A SUPPORTED PLATFORM are supported under Windows. NO OTHER DEVICES CAN BE USED FOR PACKET CAPTURE. airpcap Airpcap generic source. Will autodetect the channel ranges. Interface 'airpcap' will detect the first airpcap device (ncsource=airpcap), interface paths may be used to specify specific devices (ncsource=\\.\airpcap01) airpcap_ask List available sources and ask which one to use. Should NOT be used when launched by the Kismet UI. pcapfile Pcap-formatted previously recorded file drone Remote Kismet packet capture, source options "host=..." and "port=..." are required. OSX/Macintosh Capture Sources: darwin Any device controlled by the Airport IOKit drivers under OSX. Default 802.11b/g channels. pcapfile Pcap-formatted previously recorded file drone Remote Kismet packet capture, source options "host=..." and "port=..." are required. 8. Plugins Kismet plugins can do almost anything that the native Kismet process can do. This includes extending the logging capability, adding IDS alerts, defining new capture sources (within some limitations), and adding new features to the Kismet UI. Plugins need access to the Kismet source (and configuration information) to compile, and should ALWAYS be recompiled when the Kismet version changes (for those using Kismet Git development code, this may require rebuilding plugins every time a checkout is done). Plugins bundled with Kismet (and third-party plugins extracted into the Kismet source dir) can be built with 'make plugins' and installed with 'make plugins-install' or 'make plugins-userinstall'. These commands will automatically configure the plugin to compile using the current Kismet source directory, for third-party plugins compiled outside of the tree (or for manually compiling plugins), the KIS_SRC_DIR variable must be set or the symlinks to the Kismet source must be set up properly (see the README for the plugin you are trying to compile for more information). "Restricted" plugins, which provide potentially invasive behavior such as auto-guessing WEP based by the SSID or automatically running the PTW WEP attack against captured data can be compiled and installed with: make restricted-plugins make restricted-plugins-install -or- make restricted-plugins-userinstall Plugins for the Kismet server (capture and logging process) are loaded from the system-wide plugin directory (/usr/local/lib/kismet/ by default) or from the users Kismet settings directory (~/.kismet/plugins). When running Kismet with privilege separation enabled (installed kismet_capture as root), plugins are only loaded by the Kismet server process and not the root-level Kismet capture process, and plugins cannot perform tasks that require root privileges. When running Kismet without privilege separation (launching as root), plugins run with root privileges. This is not recommended. Server plugins are only loaded when kismet.conf contains: allowplugins=true Client plugins are loaded from the system-wide plugin directory (/usr/local/lib/kismet_client by default) or from the users Kismet settings directory (~/.kismet/client_plugins). The Kismet UI provides mechanisms for loading plugins (and specifying plugins to be loaded automatically on startup) via the Plugins menu item. Once a Kismet UI plugin is loaded, it cannot be unloaded. To unload a Kismet plugin, go to the Plugins window, configure the plugin to not load on start, and restart Kismet. To configure plugin loading in the UI, select the plugin (the list is automatically generated from plugins installed in the system and user plugin directories) and press enter. Plugins will be loaded when the plugin window is closed. Kismet server plugins cannot currently be manipulated via the Kismet UI, but loaded plugins will be displayed. If a plugin causes startup problems (most likely because it was compiled for a different Kismet binary), Kismet will exit and explain which plugin caused the crash during startup. Plugins may also cause instability during runtime; if runtime crashes occur while plugins are loaded, remove them and re-test. Often, recompiling the plugins against the running Kismet source will help resolve these issues. 9. GPS Kismet can integrate with a GPS device to provide coordinates for networks it has detected. These can be logged to the pcap file when PPI logging is enabled, and to an XML file for processing with Kismap, included with the Kismet source, as well as other third-party tools. Kismet can use the GPS network daemon 'gpsd', or can parse NMEA directly from the GPS unit. The GPS is controlled with the Kismet server config, kismet.conf. For using gpsd with gpsd running on the local system: gps=true gpstype=gpsd gpshost=localhost:2947 gpsmodelock=false gpsreconnect=true By specifying gpsreconnect, if gpsd crashes or Kismet otherwises looses its connection, it will be re-established. Gpsmodelock compensates for certain broken GPS/GPSd combinations, where the GPS never reports a valid lock. By forcing a gpsmodelock=true, Kismet assumes the GPS always has a 2d lock. For using a GPS device without gpsd: gps=true gpstype=serial gpsdevice=/dev/ttyS0 gpsreconnect=true The gpsdevice parameter should be set to the proper serial device for your GPS. For USB GPS devices this will typically be /dev/ttyUSB0, and for bluetooth devices this will often by /dev/rfcomm0 or similar. Check the output of "dmesg" after plugging in your device. Kismet cannot know the location of a network, it can only know the location where it saw a signal. By circling the suspected location, you can provide more GPS data for processing the network center point. Kismet keeps running averages of the network location, however this is not incredibly accurate, due to averaging and imprecision in floating point math. For plotting network locations, the GPSXML file should be used. 10. Logging By default Kismet will log the pcap file, gps log, alerts, and network log in XML and plaintext. By default, Kismet will try to log to pcapfiles using the PPI per-packet header. The PPI header is a well-documented header supported by Wireshark and other tools, which can contain spectrum data, radio data such as signal and noise levels, and GPS data. PPI is only available with recent libpcap versions. When it is not available, Kismet will fall back to standard 802.11 format with no extra headers. The pcap logging format is controlled by: pcapdumpformat=ppi or pcapdumpformat=80211 The naming of logfiles is controlled by the "logtemplate" configuration option. By default, Kismet logs in the directory it is started in (unless modified with the "--log-prefix" option). The following variables can be used in the logtemplate: %p Prefix (as given by --log-prefix) %n Logging name (as given by --log-title) %d Starting date, Mmm-DD-YYYY %D Starting date, YYYYMMDD %t Starting time, HH-MM-SS %i Incremental, in the case of multiple logs of the same name %l Log type (pcapdump, netxml, etc) %h Home directory of the user Kismet was started as The default log template with a --log-prefix of /tmp and a --log-title of Kismet would expand from: logtemplate=%p%n-%D-%t-%i.%l to (for example): /tmp/Kismet-20090428-12-45-33-1.pcapdump Nested directories may be used (for example, with a template of the form "%p/%l/%D-%t"), however they must be created prior to starting Kismet, Kismet will not create the directories itself. Most users should never need to change the logtemplate, however the option remains available. When changing the template, be sure to include the "%p" prefix option in a logical location (ie, at the beginning of the template) or else the --log-prefix argument will not function as expected. 11. Filtering Kismet supports basic filtering; networks can be excluded from tracking, pcap logging, or general logging, based on BSSID, source, or destination MAC addresses. Filters, when enabled, are "positive-pass"; anything matched by the filter will be allowed, and all other matches are excluded. To process ONLY packets to or from the network with the BSSID AA:BB:CC:DD:EE:FF: filter_tracker=BSSID(AA:BB:CC:DD:EE:FF) This behavior can be inverted by using the '!' operator. To exclude packets to or from the BSSID AA:BB:CC:DD:EE:FF: filter_tracker=BSSID(!AA:BB:CC:DD:EE:FF) Multiple MAC addresses can be stacked on the same filter line, to filter two all packets from AA:BB:CC:DD:EE:FF and 00:11:22:33:44:55: filter_tracker=BSSID(!AA:BB:CC:DD:EE:FF,!00:11:22:33:44:55) MAC addresses may also be masked in a fashion similar to IP netmasks; to process only networks of a single manufacturer: filter_tracker=BSSID(AA:BB:CC:00:00:00/FF:FF:FF:00:00:00) Similarly, SOURCE(...), DEST(...), and ANY(...) may be used to filter packets. To process only packets FROM the MAC address 11:22:33:44:55:66: filter_tracker=SOURCE(11:22:33:44:55:66) 12. Alerts & IDS Kismet includes IDS functionality, providing a stateless and stateful IDS for layer 2 and layer 3 wireless attacks. Kismet can alert on fingerprints (specific single-packet attacks) and trends (unusual probes, disassociation floods, etc). Kismet can integrate with other tools using the tun/tap export to provide a virtual network interface of wireless traffic; tools such as Packet-o-Matic and Snort can use this exported data to perform additional IDS functions. Kismet as an IDS is most effective in a stationary (ie, non-wardriving) setup, and for best results, a non-hopping source should be available on the channels the primary networks are on. Kismet IDS functions CAN be used in mobile or channel-hopping installations (and are turned on by default) but accuracy may suffer. Alerts are configured with the "alert=" configuration option in kismet.conf, and have two time parameters: Throttle, and Burst. The throttle option controls how many alerts are allowed total per time unit, while the burst option controls how many alerts are allowed in a row. For example: alert=NETSTUMBLER,5/min,1/sec Will allow 1 alert per second, at a maximum of 5 per minute. Kismet supports the following alerts, where applicable the WVE (Wireless Vulnerability and Exploits, http://www.wve.org) ID is included: AIRJACKSSID Fingerprint Deprecated The original 802.11 hacking tools, Airjack, set the initial SSID to 'airjack' when starting up. This alert is no longer relevant as the Airjack tools have long since been discontinued. APSPOOF Fingerprint A list of valid MAC addresses for a SSID may be given via the 'apspoof=' configuration file option. If a beacon or probe response for that SSID is seen from a MAC address not in that list, this alert will be raised. This can be used to detect conflicting access points, spoofed access points, or attacks such as Karma/Airbase which respond to all probe requests. The 'apspoof=' configuration option can specific exact SSID matches, regular expressions (if Kismet is compiled with PCRE support), and single, multiple, or masked MAC addresses: apspoof=Foo1:ssidregex="(?i:foobar)",validmacs=00:11:22:33:44:55 apspoof=Foo2:ssid="Foobar", validmacs="00:11:22:33:44:55,AA:BB:CC:DD:EE:FF" When multiple MAC addresses are specified, they should be enclosed in quotes (as above). For more information about forming PCRE-compatible regular expressions, see the PCRE docs (man pcrepattern). BSSTIMESTAMP Trend/Stateful Invalid/Out-of-sequence BSS Timestamps can indicate AP spoofing. APs with fluctuating BSS timestamps could be suffering an "evil twin" spoofing attack, as many tools do not attempt to sync the BSS timestamp at all, and the fine-grained nature of the BSS timestamp field makes it difficult to spoof accurately. Some APs may reset the BSS timestamp regularly, leading to a false-positive. References: WVE-2005-0019 CHANCHANGE Trend/Stateful A previously detected access point changing channels may indicate a spoofing attack. By spoofing a legitimate AP on a different channel, an attacker can lure clients to the spoofed access point. An AP changing channel during normal operation may indicate such an attack is in process, however centrally managed networks may automatically change AP channels to less-used areas of the spectrum. References: WVE-2005-0019 CRYPTODROP Trend/Stateful Spoofing an AP with less-secure encryption options may fool clients into connecting with compromised credentials. The only situation in which an access point should reduce encryption security is when the AP is reconfigured. DEAUTHFLOOD Trend/Stateful BCASTDISCON Trend/Stateful By spoofing disassociate and deauthenticate packets an attacker may disconnect clients from a network, causing a denial-of-service which lasts only as long as the attacker is able to send the packets. References: WVE-2005-0019, WVE-2005-0045, WVE-2005-0046, WVE-2005-0061 http://802.11ninja.net http://home.jwu.edu/jwright/papers/l2-wlan-ids.pdf DHCPCLIENTID Fingerprint A client which sends a DHCP DISCOVER packet containing a Client-ID tag (Tag 61) which doesn't match the source MAC of the packet may be doing a DHCP denial-of-service to exhaust the DHCP pool. DHCPCONFLICT Trend/Stateful Clients which receive a DHCP address and continue to use a different IP address may indicate a misconfigured or spoofed client. DISASSOCTRAFFIC Trend/Stateful A client which is disassociated from a network should not immediately continue exchanging data. This can indicate a spoofed client attempting to incorrectly inject data into a network, or can indicate a client being the victim of a denial-of-service attack. DISCONCODEINVALID Fingerprint DEAUTHCODEINVALID Fingerprint The 802.11 specification defines valid reason codes for disconnect and deauthenticate events. Various client and access point drivers have been reported to improperly handle invalid/undefined reason codes. DHCPNAMECHANGE Trend/Stateful DHCPOSCHANGE Trend/Stateful The DHCP configuration protocol allows clients to optionally put the hostname and DHCP client vendor/operating system in the DHCP Discover packet. These values should only change if the client has changed drastically (such as a dual-boot system). Changing values can often indicate a client spoofing/MAC cloning attack. LONGSSID Fingerprint The 802.11 specification allows a maximum of 32 bytes for the SSID. Over-sized SSIDs are indicative of an attack attempting to exploit vulnerabilities in several drivers. LUCENTTEST Fingerprint Deprecated Old Lucent Orinoco cards in certain scanning test modes generate identifiable packets. MSFBCOMSSID Fingerprint Some versions of the Windows Broadcom wireless drivers do not properly handle SSID fields longer than the 802.11 specification, leading to system compromise and code execution. This vulnerability is exploited by the Metasploit framework. References: WVE-2006-0071 MSFDLINKRATE Fingerprint Some versions of the Windows D-Link wireless drivers do not properly handle extremely long 802.11 valid rate fields, leading to system compromise and code execution. This vulnerability is exploited by the Metasploit framework. References: WVE-2006-0072 MSFNETGEARBEACON Fingerprint Some versions of the Windows netgear wireless drivers do not properly handle over-sized beacon frames, leading to system compromise and code execution. This vulnerability is exploited by the Metasploit framework. NETSTUMBLER Fingerprint Deprecated Older versions of Netstumbler (3.22, 3.23, 3.30) generate, in certain conditions, specific packets. NULLPROBERESP Fingerprint Probe-response packets with a SSID IE tag component of length 0 can cause older cards (prism2, orinoco, airport-classic) to fail. References: WVE-2005-0019 PROBENOJOIN Trend/Stateful Active scanning tools such as Netstumbler constantly send network discovery probes but never join any of the networks which respond. This alert can cause excessive false positives while channel hopping, and is disabled by default. 13. Other Configuration Kismet is divided into two main processes: kismet_server and kismet_client. The server portion (responsible for capture, logging, and decoding) is controlled by kismet.conf (by default in /usr/local/etc) and the client is configured via preferences options. For the most part, Kismet can run with no additional configuration by adding capture sources runtime with the UI, however for standalone/headless operation or advanced configuration, users will want to edit the config file. The Kismet config is a plain text file with option=value pairs. Lines beginning with # are considered comments and are ignored. Most configuration options are self-explanatory or documented in the config file itself. By default Kismet only listens to the loopback interface on port 2501. This may be changed: listen=tcp://ip:port Define the IP and port Kismet listens on. By default, for security reasons, Kismet will listen only on 127.0.0.1, the loopback interface. To listen on any interface, use the IP 0.0.0.0. allowedhosts=... Comma-separated list of IP addresses allowed to connect to the Kismet server. IP ranges may be specified with netmasks (ie 10.10.10.0/24) maxclients=N Maximum number of clients allowed to simultaneously connect to the Kismet server. maxbacklog=5000 Maximum number of backlogged "lines" the server keeps for clients which are not keeping up with the network protocol. This also affects the amount of RAM potentially used by the Kismet server process, and may need to be lowered on extremely RAM-limited systems. Kismet servers may also be configured to act as Kismet drones, exporting a TCP stream of live packets: dronelisten=.. Same as above, for drone capabilities droneallowedhosts=.. ... dronemaxclients=.. ... droneringlen=65535 Equivalent of maxbacklog for Kismet clients, maximum amount of space used for backlogged packets as a drone. May be reduced on extremely RAM-limited systems. Kismet can export packets directly to other tools by creating a virtual network interface (supported on Linux, minimal support on OSX and BSD due to limited tuntap driver implementations on these platforms): tuntap_export=true Enable tuntap export tuntap_device=kistap0 Virtual network interface created Kismet can decrypt WEP networks for which the WEP key is already known: wepkey=bssid,hexkey Only the hex key can be given, since there is no consistent method to turn a pass-phrase into a hex key for WEP for different vendors. Sound and speech can be generated by the Kismet server, however typically this would be done by the Kismet UI instead. Sound is disabled by default in the Kismet server: enablesound=true|false Play sound soundbin=... Path and options for sound player binary sound=xxx,true|false Enable playing sound trigger xxx enablespeech=true|false Speak speechbin=... Text-to-Speech player speechtype=raw|festival If using Festival (but NOT flite) speech type must be set to 'festival', all other tools should be set to 'raw' speechencoding=... NATO, Spelling, Speech. Encoding of speech fields for clarity, spell network SSIDs as NATO, spelled-out letters, or speak them normally. speech=xxx,"format" Format of spoken strings, see the Kismet UI section for more information on formatting of speech strings. The OUI file (used by Kismet to determine the manufacturer of a device) can be shared with other tools (such as Wireshark), so long as they use a compatible format. By default, Kismet searches: /etc/manuf /usr/share/wireshark/wireshark/manuf /usr/share/wireshark/manuf Additional search paths can be added with the 'ouifile=' configuration option. 14. Kismet UI The default Kismet UI uses the text-based ncurses library. Additional UIs may be available from the Links page on the Kismet website (http://www.kismetwireless.net/links.shtml) The Kismet UI functions much as any other curses application (such as Midnight Commander or Links) does. The menu is activated with 'escape', '`' or '~'. Navigation between elements of the UI is done with 'tab'. Use of a mouse is supported in much of the Kismet UI, although not all widgets fully support mouse operation. Basic use of the UI with no keyboard should be reasonable, however. The main Kismet window consists of the network list, GPS information, a summary of the current server statistics and packet source status, and the status panel where errors and announcements are printed. Additional components of the main window may be turned on with the 'View' menu. - Preferences Configuration of the Kismet UI is done entirely inside the UI via the 'Kismet->Preferences->...' menus. Preference changes are (for the most part) immediate and do not require restarting. By default, the Kismet UI will prompt on startup to launch the Kismet server, this behavior (as well as auto-connection and server setup) can be changed via the Startup and Shutdown preferences (Kismet->Preferences->Startup and Shutdown): Open Kismet server launch window automatically - Kismet will open the server startup window when the UI is loaded, if the default server is not running. Ask about launching server on startup - Ask to start a server (instead of just opening the server window) Show Kismet server console by default - Automatically open the Kismet server console window after starting the server Shut down Kismet server on exit automatically - Kill locally started servers and issue a shutdown command to remote servers when the UI exits Prompt before shutting down Kismet server - Don't kill servers without confirming Kismet menus support shortcuts, for example '~Wl' is the same as navigating to the 'Windows->Client List' menu option. - Sound and Speech The Kismet UI handles sound and speech playing for most users. Sound playing is straightforward (WAV files are installed, by default, to /usr/local/share/kismet/wav) and can be played with any sound player compatible with your install. Speech is supported on Festival and Flite. Any other text-to-speech program should work as long as it accepts plain text on standard in. Speech text is encoded depending on the type of speech event, where %1, %2, etc are replaced with data by Kismet. The supported events and replacements are: New network: 1. Network SSID encoded to speech encoding setting (spell, nato, plain) 2. Network channel 3. Network BSSID Alert: 1. Alert type GPS Lost, GPS Lock: No replacement options - Tagging networks Kismet can add custom data to a network in the form of tags. In the Kismet UI, networks and clients can both have tags added to them. These tags are displayed in the UI under network details, and logged to XML and TXT output. Tags can be set as permanent; By checking the "Remember note when restarting Kismet" checkbox in the Network and Client Note windows, the note is saved and will be re-applied to networks every time Kismet loads. Client tags are applied to a specific client in a specific network; Currently there is no mechanism for adding a note to every instance of the client. - Sorting Kismet defaults to "autofit" mode, where it tries to put as many of the currently active networks on the screen as possible. Because autofit mode is so variable, it doesn't make sense to try to allow selecting networks in autofit. To select a network and view details, first sort by another method (such as channel, time, etc) via the Sort menu, then select a network. 15. Kismet Drones Kismet Drones are designed to turn Kismet into a distributed IDS system. Drones support all of the capture methods Kismet normally supports, including multiple capture devices per drone. Drones capture wireless data and forward to a Kismet server over a secondary connection (ie, wired Ethernet). Drones do not do any decoding of packets and have minimal hardware requirements. A Kismet server connects to the drones and will provide a single Kismet UI display, packet dump, and alert generation point. Capture sources on remote Kismet drones are forwarded to the Kismet server and appear as independent capture devices which can be configured for channel hopping, locking, etc. Using the tun/tap export function, the central Kismet server can export the packets from all attached drones to a virtual network interface for use with external IDS/packet capture systems (such as Snort). To start using Drones, launch the kismet_drone process on a remote system (editing the kismet_drone.conf file to control what hosts are allowed to connect) or turn on drone capabilities in the Kismet server (by enabling the drone config options in kismet_server.conf). When running a kismet_server instance as a drone, local logging will act as usual and Kismet clients can be connected to the server as normal; When running kismet_drone, Kismet clients cannot connect directly to it, and it will not log, a Kismet server instance must be started to provide packet decoding, logging, and Kismet UI connectivity. 16. Talking to Kismet The Kismet client/server protocol is basic text. Communicating with Kismet can be as simple as using telnet or netcat, however writing a full protocol dissector is suggested for serious applications. This documents a simple case of the Kismet protocol and the basics of communicating with a Kismet server, however for detailed information the source should be consulted. A more complete documentation of the protocol will be done at some point. The Kismet protocol consists of commands and response sentences. A command is of the form: !ID COMMAND OPT1 OPT2 OPT3 Where ID is a number (which for proper error detection should be unique) and the remainder of the arguments are the command and any options it may take. Options which contain spaces but should be treated as a single argument should wrap those options in "\001...\001" And a response sentence is of the form: *HEADER: f1 f2 f3 f4 Where HEADER is the sentence type, and the remainder are fields requested by the client, in the order they were requested. Fields are expected to be plain ASCII text, however a client should take precautions to be sure that the value is sane for the terminal before printing it. Fields which may contain a space (used as the separator character) are buffered with \001...\001. As this could be any field, any protocol parser should be able to handle fields so buffered. Basic Kismet commands include: !{#} SHUTDOWN Shutdown Kismet instance !{#} CAPABILITY {Sentence} Query the accept fields for a protocol. Returns the *CAPABILITY sentence !{#} ENABLE {Sentence} {Fields}|{*} Enable a sentence, with either the provided fields and order, or all fields in the default order if * is specified. !{#} REMOVE {Sentence} Remove a sentence. Stop sending a sentence. !{#} ADDNETTAG {BSSID} {Permanent} {Tag name} {Tag content} Add an arbitrary tag to a network. If permanent, it will be cached in ~/.kismet/tags.conf !{#} DELNETTAG {BSSID} {Tag name} Remove a tag !{#} ADDCLITAG {BSSID} {MAC} {Permanent} {Tag} {Content} Add tag to specified client in network !{#} DELCLITAG {BSSID} {MAC} {Tag} Remove a tag !{#} ADDSOURCE {source line} Add a source dynamically. Source line should be of the same format as a 'ncsource=' config line Protocol sentences: When a sentence is enabled, any existing sentence data is sent (at the discretion of the protocol handlers). Additional data is sent in the form of deltas; To conserve bandwidth and processing time, only instances where the data has changed are sent. For example, when the *BSSID sentence is sent, a block of *BSSID records are sent, for all networks previously detected by Kismet. Until the sentence is disabled, a record is sent once per second for each network which has changed in some fashion (new packets). Mandatory sentences: Kismet expects a client to support AT LEAST the following mandatory protocols, which are enabled by default. At the very least, any client should ignore these if it does not process them. They may be disabled with the REMOVE command. In general, any client should ignore protocols it does not understand. *KISMET Basic Kismet startup info *PROTOCOLS List of supported sentences *ACK Command response *ERROR Command failure *TIME Server timestamp Example: echo -e '\n!0 enable channel channel,networks' | nc localhost 2501 Enable the *CHANNEL sentence with the fields 'channel' and 'networks'. The output could look something like: *ACK: 0 OK *CHANNEL: 1 4 *CHANNEL: 3 1 *CHANNEL: 4 1 *TIME: 1245176426 17. Troubleshooting Congratulations! You're actually reading the troubleshooting section of the README! Many don't. If you are having trouble getting Kismet to capture packets at all, launch kismet_server independently of the client and watch the output, it may be easier to spot problems then. Some common problems with Kismet have easy solutions: PROBLEM: Fatal errors about old configuration files/missing config values Kismet has evolved over time, and has recently had a significant rewrite of the entire application, rendering many of the old configuration values obsolete, and changing many others. FIX: Update your config files. If you are moving to the latest release of Kismet, it may be best to just remove your old config files, copy the new ones, and reconfigure. PROBLEM: Kismet crashes immediately while starting up FIX: If you are building Kismet from SVN routinely, it's possible that the build system has gotten screwed up with a recent change. Run 'make distclean' then './configure' and 'make' again. If the kismet_capture binary is out-of-sync with the kismet_server or kismet_drone binaries, things will behave oddly. PROBLEM: Kismet shows FATAL errors about permission denied FIX: Are you trying to capture from a network interface without root privileges? Kismet must either be installed as suid-root (and the user starting it must be in the kismet group) or it must be started as root, see the "Suid Root & Security" section of the README. PROBLEM: Kismet can not autodetect my card type or doesn't understand the "type=..." source option. FIX: Some drivers do not register with the /sys filesystem and can not be properly autodetected. Check the list of capture sources known to be problematic in this README. Secondly, check the output of './configure' when building Kismet and make sure that support for your capture type is present, most commonly support for pcap or wext is missing. PROBLEM: Kismet warns about interfering processes while starting up. Many network services can interfere with Kismet (DHCP, networkmanager, etc) by reconfiguring or shutting down the network interface while Kismet is running. FIX: Only necessary if Kismet is not behaving as expected, or encountering errors. Shutdown or kill the offending processes. This can often be most quickly accomplished by stopping the networking services for your interface ('ifdown wlan0' for example). In some specific configurations, these alerts may be spurious (dhcp and wpa_supplicant alerts on a multi-vap mac80211 interface doing sta+rfmon with a wpa_supplicant scanning option, for example). PROBLEM: Kismet complains about multiple VAPs under madwifi-ng FIX: Destroy the other VAPs, or ignore this warning if there are no run-time failures. Madwifi-ng has historically had significant problems with multi-vap and rfmon (for example, a STA VAP and a RFMON VAP). PROBLEM: Shortly after starting on madwifi-ng, Kismet stops reporting packets. FIX: There appears to be a race condition in madwifi-ng startup where an autocreated VAP causes errors in future VAPs. A temporary fix is to reload the madwifi-ng driver before starting Kismet, with the 'autocreate=none' modparm ('rmmod ath_pci; modprobe ath_pci autocreate=none'), a more permanent fix is to put this in the default module parameters for ath_pci and make the necessary changes to your startup scripts to create a managed VAP on startup. PROBLEM: './configure' is unable to find libpcap, wext, ncurses, pcre, or some other library when building from source. FIX: Many distributions separate the runtime data from the data necessary to compile programs against a library. Install the '-dev' or '-devel' or 'devel-' packages for each of the libraries ('apt-get install libpcap-dev' for example) PROBLEM: Kismet exits immediately on Cygwin with no output. FIX: Cygwin appears to have problems linking static libraries when they are not in a sub-directory of the build. By default, './configure' will look in "Airpcap_Devpack" and "Winpcap_Devpack", you should probably just expand the devpack zips there. PROBLEM: I can't capture on (some device that isn't an AirPCAP that I bought from CACE) on Windows! FIX: Buy an AirPCAP and read the docs. PROBLEM: I can't see some parts of the Kismet UI FIX: Some terminals have bad default color assignments and render dark grey as black. Go into the Kismet color preferences and change the items. PROBLEM: A plugin crashes Kismet (server or UI) FIX: Recompile the plugin and make sure it's build with the same code as the Kismet server/client. This is especially problematic if you are following Kismet development in SVN. PROBLEM: Kismet makes the mouse slow or crashes the whole system FIX: This isn't actually Kismet. Only the kernel layer should be able to cause the system to lockup or crash, or interfere with interrupts so badly that the mouse becomes unresponsive. Kismet may exacerbate this behavior by changing the card configuration and exposing flaws in the driver; This most often can happen while changing channels, try disabling channel hopping (or slowing it down), and upgrade to the latest drivers for your device. PROBLEM: Kismet cannot open a source, with the error: "can't get usb bus index" FIX: Some versions of LibPcap interpret any interface with "USB" in the name as a USB device on Linux, and attempt to do USB bus capture instead of packet capture. Rename the interface (with ifrename or udev rules) to something that doesn't include 'usb'. A newer version of libpcap may also resolve this problem. PROBLEM: configure cannot find libnl on Ubuntu, but libnl-dev is installed FIX: Some distributions (apparently, Ubuntu) require libnfnetlink-dev to be installed as well. Currently there is no good way to autodetect this. 18. Frequently Asked Questions Q: Where did the name Kismet come from? A: 'Kismet' means 'Fate' or 'Destiny'; While I wish I could take credit for some plan about picking it for Kismets ability to uncover any network in the area, I really just needed a name and clicked through a thesaurus until I found a word that wasn't used in any other OSS projects. Q: Is there anything illegal about Kismet? A: In and of itself, there should be nothing illegal about Kismet (it's fundamentally no different than any other capture tool) but you should check your local laws first. Note, however: - Recording data from networks that you do not have permission to may be considered an illegal wiretap. - Using networks you do not have permission to use may be considered 'Theft of Service' and is illegal. - Don't be stupid. - If you are stupid, I'm not responsible. Q: Can Kismet crack WEP? A: Yes, but also, no. The base Kismet code does not do any WEP cracking, however due to constant requests, there IS an Aircrack-PTW plugin which will do PASSIVE WEP cracking only. It will NOT do arp-replay, fragmentation, or other active attacks, however if enough packets are gathered it will attempt to crack the WEP key and insert it into Kismet to decrypt that network. The PTW-WEP cracking plugin is in the Kismet source tree in the plugin-ptw/ directory. Q: What's the deal with Newcore, and where did it go? A: Newcore was a total rewrite of Kismet, which lasted years longer in a development state than planned. If you're reading this, you've got the release that Newcore became already. Q: What happened to the version numbers? A: They stopped making sense. 3.0 to 3.1 was a 30,000 line change, but calling it 4.0 didn't make any sense either. I hate project perpetually in 0.1, 0.9 status, but I also hate artificially expanding the version numbers. So, now, it's versioned by the release date, YYYY-MM-RR. Q: Can I use the old Kismet UI still? A: No, sorry, too much has changed in the protocols, and the new UI is much more flexible anyhow Q: Can I use the old drones still? A: No, again, too much has changed (however from now on it should be possible to mix versions since the drone protocol has been expanded to be expandable) Q: What is RFMON/Monitor mode? A: In the wired world, promiscuous mode turns off the filtering mechanism in the device and reports all packets on the Ethernet (or whatever) layer. With wireless drivers, this doesn't necessarily mean anything (sometimes it causes different results, sometimes it doesn't). Wireless drivers present a fake Ethernet device to the operating systems, which reports only 802.11 data frames. When looking at WPA encrypted networks, this is even more limited, because packets are encrypted for each client and only multicast/broadcast packets or packets destined to the capture device could be reported as valid data frames anyhow. Monitor/RFMON mode is a special mode for wireless devices which reports all packets the card sees, with the 802.11 headers intact, including 802.11 management and control frames. Q: Does Kismet work differently than NetStumbler? A: Absolutely. Netstumbler (and Ministumbler, InSSIDer, etc) work by instructing the card to probe for networks and report the networks the card sees responses from. This method is obviously competent at detecting networks in the area, however it can't record data, find hidden networks, detect clients using networks, etc. Q: Why are some probe SSIDs full of strange nonsense characters? A: It appears with Windows Zero Config in many versions of Windows XP has an off-by-one error which leaks a little bit of memory into a probe request. Q: Why is the range of a network sometimes totally bogus when using a GPS with Kismet? A: Doing real-time GPS averaging leads to increasingly bad data due to floating-point accuracy and averaging. For more exact GPS data, process the gpsxml file. Q: What happened to gpsmap? A: gpsmap was the old mapper code for Kismet. It stopped being useful a long time ago when the map sources it used went away. It's being replaced with a tile-based mapper, the beginnings of which are in the kismap/ directory in the source code. Kismap isn't quite finished for the RC1 release, but development continues on it and it will be available hopefully soon. Q: How can I merge multiple capture files? A: Use the 'mergecap' tool that comes with Wireshark. Q: How can I support device X with Kismet on operating system Y? A: Kismet is designed to be fairly modular (especially the newest versions based on Newcore). So long as your environment is something like Posix and your device supports raw capture modes, it should be possible. Swing by IRC (#kismet on freenode) and chat. Q: Why does Kismet make a new interface named foo-mon? A: When mac80211 is available, Kismet will use to create a new virtual interface, named after the existing interface (wlan0 for instance will cause a wlan0mon to be created). Kismet will use this virtual interface for capture, so that it causes less disruption to the configuration of the existing interface. Q: What happens when I ask a question already here? A: I'll probably be rude to you (or someone else will). But that would never happen, because everyone reads the docs all the way to the end, right? Right!? ���������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/kismet_drone.cc������������������������������������������������������������������0000664�0001750�0001750�00000046737�12124602454�016466� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #define KISMET_DRONE #include "version.h" #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include "getopt.h" #include <stdlib.h> #include <signal.h> #include <pwd.h> #include <string> #include <vector> #include "util.h" #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "plugintracker.h" #include "packetsource.h" #include "packetsource_bsdrt.h" #include "packetsource_pcap.h" #include "packetsource_wext.h" #include "packetsource_drone.h" #include "packetsource_ipwlive.h" #include "packetsource_airpcap.h" #include "packetsource_darwin.h" #include "packetsource_macusb.h" #include "packetsourcetracker.h" #include "timetracker.h" #include "netframework.h" #include "tcpserver.h" // Include the stubbed empty netframe code #include "kis_netframe.h" #include "kis_droneframe.h" #include "gpswrapper.h" #include "ipc_remote.h" #ifndef exec_name char *exec_name; #endif // Daemonize? int daemonize = 0; // One of our few globals in this file int glob_linewrap = 1; int glob_silent = 0; // Message clients that are attached at the master level // Smart standard out client that understands the silence options class SmartStdoutMessageClient : public MessageClient { public: SmartStdoutMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~SmartStdoutMessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; void SmartStdoutMessageClient::ProcessMessage(string in_msg, int in_flags) { if (glob_silent) return; if ((in_flags & MSGFLAG_DEBUG)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("DEBUG: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "DEBUG: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_LOCAL)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("LOCAL: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "LOCAL: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_INFO)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("INFO: " + in_msg, 6, 80).c_str()); else fprintf(stdout, "INFO: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ERROR)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ERROR: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "ERROR: %s\n", in_msg.c_str()); } else if ((in_flags & MSGFLAG_ALERT)) { if (glob_linewrap) fprintf(stdout, "%s", InLineWrap("ALERT: " + in_msg, 7, 80).c_str()); else fprintf(stdout, "ALERT: %s\n", in_msg.c_str()); } else if (in_flags & MSGFLAG_FATAL) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap("FATAL: " + in_msg, 7, 80).c_str()); else fprintf(stderr, "FATAL: %s\n", in_msg.c_str()); } return; } // Queue of fatal alert conditions to spew back out at the end class FatalQueueMessageClient : public MessageClient { public: FatalQueueMessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { } virtual ~FatalQueueMessageClient() { } void ProcessMessage(string in_msg, int in_flags); void DumpFatals(); protected: vector<string> fatalqueue; }; void FatalQueueMessageClient::ProcessMessage(string in_msg, int in_flags) { // We only get passed fatal stuff so save a test fatalqueue.push_back(in_msg); } void FatalQueueMessageClient::DumpFatals() { for (unsigned int x = 0; x < fatalqueue.size(); x++) { if (glob_linewrap) fprintf(stderr, "%s", InLineWrap("FATAL: " + fatalqueue[x], 7, 80).c_str()); else fprintf(stderr, "FATAL: %s\n", fatalqueue[x].c_str()); } } const char *config_base = "kismet_drone.conf"; const char *pid_base = "kismet_drone.pid"; // This needs to be a global but nothing outside of this main file will // use it, so we don't have to worry much about putting it in the globalreg. FatalQueueMessageClient *fqmescli = NULL; // Some globals for command line options char *configfile = NULL; // Ultimate registry of global components GlobalRegistry *globalregistry = NULL; // Catch our interrupt void CatchShutdown(int sig) { string termstr = "Kismet drone terminating."; if (globalregistry->sourcetracker != NULL) { // Shut down the packet sources globalregistry->sourcetracker->StopSource(0); } if (globalregistry->plugintracker != NULL) globalregistry->plugintracker->ShutdownPlugins(); // Start a short shutdown cycle for 2 seconds if (daemonize == 0) fprintf(stderr, "\n*** KISMET DRONE IS FLUSHING BUFFERS AND SHUTTING DOWN ***\n"); globalregistry->spindown = 1; time_t shutdown_target = time(0) + 2; int max_fd = 0; fd_set rset, wset; struct timeval tm; while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) { break; } if (time(0) >= shutdown_target) { break; } // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { break; } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { break; } } } if (globalregistry->rootipc != NULL) { // Shut down the channel control child globalregistry->rootipc->ShutdownIPC(NULL); } // Be noisy if (globalregistry->fatal_condition && daemonize == 0) { fprintf(stderr, "\n*** KISMET DRONE HAS ENCOUNTERED A FATAL ERROR AND CANNOT " "CONTINUE. ***\n"); } // Dump fatal errors again if (fqmescli != NULL) fqmescli->DumpFatals(); if (daemonize == 0) fprintf(stderr, "Kismet drone exiting.\n"); exit(0); } int Usage(char *argv) { printf("Usage: %s [OPTION]\n", argv); printf("Nearly all of these options are run-time overrides for values in the\n" "kismet.conf configuration file. Permanent changes should be made to\n" "the configuration file.\n"); printf(" *** Generic Options ***\n"); printf(" -f, --config-file Use alternate configuration file\n" " --no-line-wrap Turn of linewrapping of output\n" " (for grep, speed, etc)\n" " -s, --silent Turn off stdout output after setup phase\n" " --daemonize Spawn detatched in the background\n" ); printf("\n"); KisDroneFramework::Usage(argv); printf("\n"); Packetsourcetracker::Usage(argv); exit(1); } int main(int argc, char *argv[], char *envp[]) { exec_name = argv[0]; char errstr[STATUS_MAX]; char *configfilename = NULL; ConfigFile *conf; int option_idx = 0; GlobalRegistry *globalreg = NULL; int startup_ipc_id = -1; int max_fd = 0; fd_set rset, wset; struct timeval tm; // ------ WE MAY BE RUNNING AS ROOT ------ // Catch the interrupt handler to shut down signal(SIGINT, CatchShutdown); signal(SIGTERM, CatchShutdown); signal(SIGHUP, CatchShutdown); signal(SIGPIPE, SIG_IGN); // Start filling in key components of the globalregistry globalregistry = new GlobalRegistry; globalreg = globalregistry; globalregistry->version_major = VERSION_MAJOR; globalregistry->version_minor = VERSION_MINOR; globalregistry->version_tiny = VERSION_TINY; globalregistry->revision = REVISION; globalregistry->revdate = REVDATE; // Copy for modules globalregistry->argc = argc; globalregistry->argv = argv; globalregistry->envp = envp; // Turn off the getopt error reporting opterr = 0; // Timer for silence int local_silent = 0; const int nlwc = globalregistry->getopt_long_num++; const int dwc = globalregistry->getopt_long_num++; // Standard getopt parse run static struct option main_longopt[] = { { "config-file", required_argument, 0, 'f' }, { "no-line-wrap", no_argument, 0, nlwc }, { "silent", no_argument, 0, 's' }, { "help", no_argument, 0, 'h' }, { "daemonize", no_argument, 0, dwc }, { 0, 0, 0, 0 } }; while (1) { int r = getopt_long(argc, argv, "-f:sh", main_longopt, &option_idx); if (r < 0) break; if (r == 'h') { Usage(argv[0]); exit(1); } else if (r == 'f') { configfilename = strdup(optarg); } else if (r == nlwc) { glob_linewrap = 0; } else if (r == 's') { local_silent = 1; } else if (r == dwc) { daemonize = 1; local_silent = 1; } } // First order - create our message bus and our client for outputting globalregistry->messagebus = new MessageBus; // Create a smart stdout client and allocate the fatal message client, // add them to the messagebus SmartStdoutMessageClient *smartmsgcli = new SmartStdoutMessageClient(globalregistry, NULL); fqmescli = new FatalQueueMessageClient(globalregistry, NULL); globalregistry->messagebus->RegisterClient(fqmescli, MSGFLAG_FATAL); globalregistry->messagebus->RegisterClient(smartmsgcli, MSGFLAG_ALL); #ifndef SYS_CYGWIN if (getuid() != 0) { globalregistry->messagebus->InjectMessage("Not running as root - will try to " "launch root control binary (" + string(BIN_LOC) + "/kismet_capture) to " "control cards.", MSGFLAG_INFO); globalregistry->rootipc = new RootIPCRemote(globalregistry, "kismet_root"); globalregistry->rootipc->SpawnIPC(); startup_ipc_id = globalregistry->rootipc->RegisterIPCCmd(NULL, NULL, NULL, "STARTUP"); time_t ipc_spin_start = time(0); while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } if (globalregistry->rootipc->FetchRootIPCSynced() > 0) { // printf("debug - kismet server startup got root sync\n"); break; } if (time(0) - ipc_spin_start > 2) { // printf("debug - kismet server startup timed out\n"); break; } } if (globalregistry->rootipc->FetchRootIPCSynced() <= 0) { critical_fail cf; cf.fail_time = time(0); cf.fail_msg = "Failed to start kismet_capture control binary. Make sure " "that kismet_capture is installed, is suid-root, and that your user " "is in the 'kismet' group, or run Kismet as root. See the " "README for more information."; int ipc_errno = globalregistry->rootipc->FetchErrno(); if (ipc_errno == EPERM || ipc_errno == EACCES) { cf.fail_msg = "Could not launch kismet_capture control binary, " "due to permission errors. To run Kismet suid-root your user " "MUST BE IN THE 'kismet' GROUP. Use the 'groups' command to show " "what groups your user is in, and consult the Kismet README for " "more information."; } globalreg->critfail_vec.push_back(cf); _MSG(cf.fail_msg, MSGFLAG_FATAL); } else { _MSG("Started kismet_capture control binary successfully, pid " + IntToString(globalreg->rootipc->FetchSpawnPid()), MSGFLAG_INFO); } } else { globalregistry->messagebus->InjectMessage( "Kismet was started as root, NOT launching external control binary. " "This is NOT the preferred method of starting Kismet as Kismet will " "continue to run as root the entire time. Please read the README " "file section about Installation & Security and be sure this is " "what you want to do.", MSGFLAG_ERROR); } #endif // Allocate some other critical stuff globalregistry->timetracker = new Timetracker(globalregistry); // Open, initial parse, and assign the config file if (configfilename == NULL) { configfilename = new char[1024]; snprintf(configfilename, 1024, "%s/%s", getenv("KISMETDRONE_CONF") != NULL ? getenv("KISMETDRONE_CONF") : SYSCONF_LOC, config_base); } snprintf(errstr, STATUS_MAX, "Reading from config file %s", configfilename); globalregistry->messagebus->InjectMessage(errstr, MSGFLAG_INFO); conf = new ConfigFile(globalregistry); if (conf->ParseConfig(configfilename) < 0) { exit(1); } globalregistry->kismet_config = conf; if (daemonize) { if (fork() != 0) { fprintf(stderr, "Silencing output and entering daemon mode...\n"); exit(1); } // remove messagebus clients globalregistry->messagebus->RemoveClient(fqmescli); globalregistry->messagebus->RemoveClient(smartmsgcli); } if (conf->FetchOpt("servername") == "") { char hostname[64]; if (gethostname(hostname, 64) < 0) globalregistry->servername = "Kismet Drone"; else globalregistry->servername = string(hostname); } else { globalregistry->servername = MungeToPrintable(conf->FetchOpt("servername")); } // Create the stubbed network/protocol server globalregistry->kisnetserver = new KisNetFramework(globalregistry); // Start the plugin handler globalregistry->plugintracker = new Plugintracker(globalregistry); // Build the plugin list for root plugins globalregistry->plugintracker->ScanRootPlugins(); // Create the packet chain globalregistry->packetchain = new Packetchain(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Create the packetsourcetracker globalregistry->sourcetracker = new Packetsourcetracker(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Register the IPC if (globalregistry->rootipc != NULL) { globalregistry->sourcetracker->RegisterIPC(globalregistry->rootipc, 0); globalregistry->rootipc->SyncRoot(); globalregistry->rootipc->SyncIPC(); ipc_packet *ipc = (ipc_packet *) malloc(sizeof(ipc_packet)); ipc->data_len = 0; ipc->ipc_ack = 0; ipc->ipc_cmdnum = startup_ipc_id; globalreg->rootipc->SendIPC(ipc); } // Create the basic drone server globalregistry->kisdroneserver = new KisDroneFramework(globalregistry); if (globalregistry->fatal_condition || globalregistry->kisdroneserver->Valid() == 0) CatchShutdown(-1); // Add the packet sources #ifdef USE_PACKETSOURCE_PCAPFILE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Pcapfile(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WEXT if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Wext(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFI if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Madwifi(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MADWIFING if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_MadwifiNG(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_WRT54PRISM if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Wrt54Prism(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DRONE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Drone(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_BSDRT if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_BSDRT(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_IPWLIVE if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Ipwlive(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_AIRPCAP if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_AirPcap(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_DARWIN if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_Darwin(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif #ifdef USE_PACKETSOURCE_MACUSB if (globalregistry->sourcetracker->RegisterPacketSource(new PacketSource_MacUSB(globalregistry)) < 0 || globalregistry->fatal_condition) CatchShutdown(-1); #endif // Enable cards from config/cmdline if (globalregistry->sourcetracker->LoadConfiguration() < 0) CatchShutdown(-1); // Create the basic network/protocol server globalregistry->kisdroneserver->Activate(); if (globalregistry->fatal_condition) CatchShutdown(-1); // Once the packet source and channel control is opened, we shouldn't need special // Process userspace plugins globalregistry->plugintracker->ScanUserPlugins(); // Create the GPS components GpsWrapper *gpswrapper; globalregistry->messagebus->InjectMessage("Starting GPS components...", MSGFLAG_INFO); gpswrapper = new GpsWrapper(globalregistry); if (globalregistry->fatal_condition) CatchShutdown(-1); // Kick the plugin system one last time. This will try to kick any plugins // that aren't activated yet, and then bomb out if we can't turn them on at // all. globalregistry->plugintracker->LastChancePlugins(); if (globalregistry->fatal_condition) CatchShutdown(-1); // Initialize the crc tables crc32_init_table_80211(globalregistry->crc32_table); // Blab about starting globalregistry->messagebus->InjectMessage("Kismet drone starting to gather " "packets", MSGFLAG_INFO); // Start sources globalregistry->sourcetracker->StartSource(0); // Set the global silence now that we're set up glob_silent = local_silent; // Core loop while (1) { FD_ZERO(&rset); FD_ZERO(&wset); max_fd = 0; if (globalregistry->fatal_condition) CatchShutdown(-1); // Collect all the pollable descriptors for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) max_fd = globalregistry->subsys_pollable_vec[x]->MergeSet(max_fd, &rset, &wset); tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { snprintf(errstr, STATUS_MAX, "Main select loop failed: %s", strerror(errno)); CatchShutdown(-1); } } globalregistry->timetracker->Tick(); for (unsigned int x = 0; x < globalregistry->subsys_pollable_vec.size(); x++) { if (globalregistry->subsys_pollable_vec[x]->Poll(rset, wset) < 0 && globalregistry->fatal_condition) { CatchShutdown(-1); } } } CatchShutdown(-1); } ���������������������������������kismet-2013-03-R1b/dumpfile_pcap.h������������������������������������������������������������������0000664�0001750�0001750�00000006473�12124602454�016446� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __DUMPFILE_PCAP_H__ #define __DUMPFILE_PCAP_H__ #include "config.h" #ifdef HAVE_LIBPCAP #include <stdio.h> #include <string> extern "C" { #ifndef HAVE_PCAPPCAP_H #include <pcap.h> #else #include <pcap/pcap.h> #endif } #include "globalregistry.h" #include "configfile.h" #include "messagebus.h" #include "packetchain.h" #include "dumpfile.h" // Hook for grabbing packets int dumpfilepcap_chain_hook(CHAINCALL_PARMS); enum dumpfile_pcap_format { dump_unknown, dump_dlt, dump_ppi }; // Plugin/module PPI callback // This is a little wonky; each callback function will be called twice, once with // allocate set to 1 to indicate how much space it will require in the PPI header, // and once with the partial header and offset to fill it in. The return value when // called with allocate should be the amount of space it will use, while the // return value for non-allocate should indicate the new position (absolute new // position, not offset!) #define DUMPFILE_PPI_PARMS GlobalRegistry *in_globalreg, int in_allocate, \ kis_packet *in_pack, uint8_t *dump_data, int dump_pos, void *aux typedef int (*dumpfile_ppi_cb)(DUMPFILE_PPI_PARMS); // Filter to return a packet type for logging (used for derivative pcap loggers, // like in plugins) #define DUMPFILE_PCAP_FILTER_PARMS GlobalRegistry *in_globalreg, kis_packet *in_pack, \ void *aux typedef kis_datachunk *(*dumpfile_pcap_filter_cb)(DUMPFILE_PCAP_FILTER_PARMS); // Pcap-based packet writer class Dumpfile_Pcap : public Dumpfile { public: Dumpfile_Pcap(); Dumpfile_Pcap(GlobalRegistry *in_globalreg); // Alternate constructor for custom pcap logs (ie plugins) // New type overrides 'pcapdump'. // Passing a pointer to a "parent" pcapfile will attach and share // callbacks for the PPI system, in a fugly nasty way. Dumpfile_Pcap(GlobalRegistry *in_globalreg, string in_type, int in_dlt, Dumpfile_Pcap *in_parent, dumpfile_pcap_filter_cb in_filter, void *in_aux); virtual ~Dumpfile_Pcap(); virtual int chain_handler(kis_packet *in_pack); virtual int Flush(); virtual void RegisterPPICallback(dumpfile_ppi_cb in_cb, void *in_aux); virtual void RemovePPICallback(dumpfile_ppi_cb in_cb, void *in_aux); struct ppi_cb_rec { dumpfile_ppi_cb cb; void *aux; }; protected: Dumpfile_Pcap *parent; // Common internal startup void Startup_Dumpfile(); pcap_t *dumpfile; pcap_dumper_t *dumper; int beaconlog, phylog, corruptlog; dumpfile_pcap_format dumpformat; int dlt; macmap<uint32_t> bssid_csum_map; vector<ppi_cb_rec> ppi_cb_vec; dumpfile_pcap_filter_cb cbfilter; void *cbaux; }; #endif /* pcap */ #endif /* __dump... */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/configure������������������������������������������������������������������������0000775�0001750�0001750�00000740340�12124602454�015372� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 </dev/null exec 6>&1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="kismet.h" ac_unique_file="kismet_server.cc" # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #ifdef STDC_HEADERS # include <stdlib.h> # include <stddef.h> #else # ifdef HAVE_STDLIB_H # include <stdlib.h> # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include <memory.h> # endif # include <string.h> #endif #ifdef HAVE_STRINGS_H # include <strings.h> #endif #ifdef HAVE_INTTYPES_H # include <inttypes.h> #endif #ifdef HAVE_STDINT_H # include <stdint.h> #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif" ac_subst_vars='LTLIBOBJS sharedatadir KSLIBS threadlib suidgroup libnl1_LIBS libnl1_CFLAGS libnl20_LIBS libnl20_CFLAGS libnlgenl30_LIBS libnlgenl30_CFLAGS libnl30_LIBS libnl30_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG havepkgconfig pcap pcaplnk wantpcap caplibs CLIENTCFLAGS CLIENTCLIBS CLIBS wantclient mangrp instgrp CXXLIBS LIBOBJS EGREP GREP objc_link PLUGINLDFLAGS CPP SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_largefile enable_client with_linuxheaders enable_linuxwext with_pcreheaders enable_pcre enable_airpcap with_airpcap_devpack with_winpcap_devpack enable_pcap with_netlink_version with_suidgroup enable_optimization ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR libnl30_CFLAGS libnl30_LIBS libnlgenl30_CFLAGS libnlgenl30_LIBS libnl20_CFLAGS libnl20_LIBS libnl1_CFLAGS libnl1_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-largefile omit support for large files --disable-client disable kismet client --disable-linuxwext disable Linux wireless extensions --disable-pcre disable building pcre components --enable-airpcap enable checking for CACE airpcap --disable-pcap disable libpcap (most sources) capture support --disable-optimization disable -Ox gcc optimization Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-linuxheaders=DIR Custom location of the Linux kernel headers if the glibc copies are insufficient --with-pcreheaders=DIR Custom location of the PCRE library headers --with-airpcap=DIR Location of the CACE AirPcap device pack NOTE cygwin appears to have link errors if the path is not within the current directory --with-winpcap=DIR Location of the WinPcap device pack NOTE cygwin appears to have link errors if the path is not within the current directory --with-netlink-version=1|2|3 Force using libnl1, libnl2, or libnl-3 --with-suidgroup=group Group allowed to execute the kismet_capture suid root helper process Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> LIBS libraries to pass to the linker, e.g. -l<library> CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path libnl30_CFLAGS C compiler flags for libnl30, overriding pkg-config libnl30_LIBS linker flags for libnl30, overriding pkg-config libnlgenl30_CFLAGS C compiler flags for libnlgenl30, overriding pkg-config libnlgenl30_LIBS linker flags for libnlgenl30, overriding pkg-config libnl20_CFLAGS C compiler flags for libnl20, overriding pkg-config libnl20_LIBS linker flags for libnl20, overriding pkg-config libnl1_CFLAGS C compiler flags for libnl1, overriding pkg-config libnl1_LIBS linker flags for libnl1, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case <limits.h> declares $2. For example, HP-UX 11i <limits.h> declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer <limits.h> to <assert.h> if __STDC__ is defined, since <limits.h> exists even on freestanding compilers. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Check for host type ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Liberated from ethereal's configure.in # # Add any platform-specific compiler flags needed. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for platform-specific compiler flags" >&5 $as_echo_n "checking for platform-specific compiler flags... " >&6; } if test "x$GCC" = x then # # Not GCC - assume it's the vendor's compiler. # case "$host_os" in hpux*) # # HP's ANSI C compiler; flags suggested by Jost Martin. # "-Ae" for ANSI C plus extensions such as "long long". # "+O2", for optimization. XXX - works with "-g"? # CFLAGS="-Ae +O2 $CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: HP ANSI C compiler - added -Ae +O2" >&5 $as_echo "HP ANSI C compiler - added -Ae +O2" >&6; } ;; darwin10*) # Snow leopard and newer, no -bundle in plugins CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' { $as_echo "$as_me:${as_lineno-$LINENO}: result: Apple OSX Snow Leopard or newer" >&5 $as_echo "Apple OSX Snow Leopard or newer" >&6; } $as_echo "#define SYS_DARWIN 1" >>confdefs.h darwin="yes" ;; darwin*) # # It may be called "cc", but it's really a GCC derivative # with a problematic special precompiler and precompiled # headers; turn off the special precompiler, as some # apparently-legal code won't compile with its precompiled # headers. # CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-bundle -flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' { $as_echo "$as_me:${as_lineno-$LINENO}: result: Apple GCC - added Apple80211 frameworks and no-precomp" >&5 $as_echo "Apple GCC - added Apple80211 frameworks and no-precomp" >&6; } $as_echo "#define SYS_DARWIN 1" >>confdefs.h darwin="yes" ;; linux*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_LINUX 1" >>confdefs.h linux="yes" ;; freebsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_FREEBSD 1" >>confdefs.h bsd="yes" ;; openbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_OPENBSD 1" >>confdefs.h bsd="yes" ;; netbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: adding pkgsrc locations" >&5 $as_echo "adding pkgsrc locations" >&6; } CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib" $as_echo "#define SYS_NETBSD 1" >>confdefs.h bsd="yes" ;; cygwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_CYGWIN 1" >>confdefs.h cygwin="yes" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; esac else case "$host_os" in solaris*) # the X11 headers don't automatically include prototype info # and a lot don't include the return type CFLAGS="$CFLAGS -Wno-return-type -DFUNCPROTO=15" { $as_echo "$as_me:${as_lineno-$LINENO}: result: GCC on Solaris - added -Wno-return-type -DFUNCPROTO=15" >&5 $as_echo "GCC on Solaris - added -Wno-return-type -DFUNCPROTO=15" >&6; } ;; darwin10*) # Snow leopard and newer, no -bundle in plugins CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" PLUGINLDFLAGS="-flat_namespace -undefined suppress" objc_link='$(OBJC_CONTROL_O)' { $as_echo "$as_me:${as_lineno-$LINENO}: result: Apple OSX Snow Leopard or newer" >&5 $as_echo "Apple OSX Snow Leopard or newer" >&6; } $as_echo "#define SYS_DARWIN 1" >>confdefs.h darwin="yes" ;; darwin*) # # See comments above about Apple's lovely C compiler. # CFLAGS="-no-cpp-precomp $CFLAGS" LDFLAGS="$LDFLAGS -framework Foundation -framework CoreFoundation -F/System/Library/PrivateFrameworks -framework Apple80211 -framework IOKit" objc_link='$(OBJC_CONTROL_O)' PLUGINLDFLAGS="-bundle -flat_namespace -undefined suppress" { $as_echo "$as_me:${as_lineno-$LINENO}: result: Apple GCC - added Apple80211 frameworks and no-precomp" >&5 $as_echo "Apple GCC - added Apple80211 frameworks and no-precomp" >&6; } $as_echo "#define SYS_DARWIN 1" >>confdefs.h darwin="yes" ;; linux*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_LINUX 1" >>confdefs.h linux="yes" ;; freebsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_FREEBSD 1" >>confdefs.h bsd="yes" ;; openbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_OPENBSD 1" >>confdefs.h bsd="yes" ;; netbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: adding pkgsrc locations" >&5 $as_echo "adding pkgsrc locations" >&6; } CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib" $as_echo "#define SYS_NETBSD 1" >>confdefs.h bsd="yes" ;; cygwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } $as_echo "#define SYS_CYGWIN 1" >>confdefs.h cygwin="yes" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; esac fi # Substitute in the objc linkages if we need them if test "$cygwin" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking cygwin compile flags" >&5 $as_echo_n "checking cygwin compile flags... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: __MINGW32__" >&5 $as_echo "__MINGW32__" >&6; } CXXFLAGS="$CXXFLAGS -D__MINGW32__" else # cygwin doesn't like rdynamic, will this hurt us? LDFLAGS="$LDFLAGS -rdynamic" fi ac_config_headers="$ac_config_headers config.h" # Config location for code to default to CONFFILE_DIR=$sysconfdir CONFFILE_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$CONFFILE_DIR" )` cat >>confdefs.h <<_ACEOF #define SYSCONF_LOC "$CONFFILE_DIR" _ACEOF LOCALSTATE_DIR=$localstatedir LOCALSTATE_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$LOCALSTATE_DIR" )` cat >>confdefs.h <<_ACEOF #define LOCALSTATE_DIR "$LOCALSTATE_DIR" _ACEOF BIN_DIR=$bindir BIN_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$BIN_DIR" )` cat >>confdefs.h <<_ACEOF #define BIN_LOC "$BIN_DIR" _ACEOF LIB_DIR=$libdir LIB_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$LIB_DIR" )` cat >>confdefs.h <<_ACEOF #define LIB_LOC "$LIB_DIR" _ACEOF DATA_DIR=$datarootdir DATA_DIR=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$DATA_DIR" )` cat >>confdefs.h <<_ACEOF #define DATA_LOC "$DATA_DIR" _ACEOF # Check for endian { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <float.h> int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <string.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ctype.h> #include <stdlib.h> #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> #include <sys/param.h> int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> #include <sys/param.h> int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <limits.h> int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <limits.h> int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac # Checks for header files. for ac_header in errno.h stdlib.h string.h sys/socket.h sys/time.h sys/wait.h unistd.h sys/types.h netdb.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF $as_echo "#define HAVE_SYSHEADERS 1" >>confdefs.h else as_fn_error $? "Missing required system header" "$LINENO" 5 fi done for ac_header in getopt.h do : ac_fn_c_check_header_mongrel "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETOPT_H 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> #include <sys/time.h> #include <time.h> int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> #include <time.h> int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi # Checks for library functions. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <float.h> int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <string.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ctype.h> #include <stdlib.h> #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if ${ac_cv_type_signal+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> #include <signal.h> int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes; then : ac_cv_func_lstat_dereferences_slashed_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 $as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && cat >>confdefs.h <<_ACEOF #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 _ACEOF if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 $as_echo_n "checking whether stat accepts an empty string... " >&6; } if ${ac_cv_func_stat_empty_string_bug+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_stat_empty_string_bug=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; return stat ("", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_stat_empty_string_bug=no else ac_cv_func_stat_empty_string_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 $as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } if test $ac_cv_func_stat_empty_string_bug = yes; then case " $LIBOBJS " in *" stat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS stat.$ac_objext" ;; esac cat >>confdefs.h <<_ACEOF #define HAVE_STAT_EMPTY_STRING_BUG 1 _ACEOF fi for ac_func in gettimeofday memset select socket strcasecmp strftime strstr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Do we have getopt_long natively? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for system-level getopt_long()" >&5 $as_echo_n "checking for system-level getopt_long()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <unistd.h> #ifdef HAVE_GETOPT_H #include <getopt.h> #endif int main () { static struct option long_options[] = { /* options table */ { "null-arg", required_argument, 0, 'n' }, { 0, 0, 0, 0 } }; int s; int option_index; int argc; char **argv; s = getopt_long(argc, argv, "n:", long_options, &option_index); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : sys_getopt=yes else sys_getopt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$sys_getopt" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GETOPT_LONG 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Look for something to define standard int types stdint=yes ac_fn_c_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes; then : $as_echo "#define HAVE_STDINT_H 1" >>confdefs.h stdint=yes else stdint=no fi if test "$stdint" = "no"; then inttypes=no ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" if test "x$ac_cv_header_inttypes_h" = xyes; then : $as_echo "#define HAVE_INTTYPES_H 1" >>confdefs.h inttypes=yes else inttypes=no fi fi if test "$stdint" = "no"; then if test "$inttypes" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } as_fn_error $? "could not find stdint.h or inttypes.h." "$LINENO" 5 fi fi # How does accept() work on this system? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for accept() addrlen type" >&5 $as_echo_n "checking for accept() addrlen type... " >&6; } OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> int main () { int s = 0; struct sockaddr *addr = NULL; socklen_t *addrlen = NULL; accept(s, addr, addrlen); return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : accept_socklen=yes else accept_socklen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$accept_socklen" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: socklen_t" >&5 $as_echo "socklen_t" >&6; } $as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: int" >&5 $as_echo "int" >&6; } fi CFLAGS="$OCFL" # Do we have large file support? # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # Do we need to use -ldl? usedl=0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : usedl=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libdl doesn't seem to be needed on this system" >&5 $as_echo "$as_me: WARNING: libdl doesn't seem to be needed on this system" >&2;} fi if test "$usedl" -eq 1; then LIBS="$LIBS -ldl" CLIENTCLIBS="$CLIENTCLIBS -ldl" fi # sqlite3=yes # AC_CHECK_HEADER([sqlite3.h], # AC_DEFINE(HAVE_SQLITE_H, 1, sqlite3.h is present) sqlite3=yes, # sqlite3=no) # # if test "$sqlite3" = yes; then # AC_CHECK_LIB([sqlite3], [sqlite3_open], # KSLIBS="$KSLIBS -lsqlite3", sqlite3=no) # fi # # if test "$sqlite3" != yes; then # AC_MSG_WARN(Failed to find sqlite3 runtime resuming will be disabled) # fi # Do we need libm for math functions? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libm math function in std libs" >&5 $as_echo_n "checking for libm math function in std libs... " >&6; } OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <math.h> int main () { double x; pow(x, x); return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : needlibm=no else needlibm=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$OCFL" if test "$needlibm" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } # Do we need to use -lm? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : LIBS="$LIBS -lm" else as_fn_error $? "libm is needed and is not available" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi # Do we use libstdc++? # We need to swap to the g++ compiler here oCC="$CC" CC="$CXX" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -luClibc++" >&5 $as_echo_n "checking for main in -luClibc++... " >&6; } if ${ac_cv_lib_uClibcpp_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-luClibc++ $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_uClibcpp_main=yes else ac_cv_lib_uClibcpp_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uClibcpp_main" >&5 $as_echo "$ac_cv_lib_uClibcpp_main" >&6; } if test "x$ac_cv_lib_uClibcpp_main" = xyes; then : foundcxxl="uclibc" CXXLIBS="$CXXLIBS -luClibc++" fi # Do we use uclibc++? if test "$foundcxxl"x == "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lstdc++" >&5 $as_echo_n "checking for main in -lstdc++... " >&6; } if ${ac_cv_lib_stdcpp_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lstdc++ $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_stdcpp_main=yes else ac_cv_lib_stdcpp_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdcpp_main" >&5 $as_echo "$ac_cv_lib_stdcpp_main" >&6; } if test "x$ac_cv_lib_stdcpp_main" = xyes; then : foundcxxl="stdc++" CXXLIBS="$CXXLIBS -lstdc++" fi fi if test "$foundcxxl"x == "x"; then as_fn_error $? "Neither uclibc uClibc++ or standard gcc stdc++ libraries found." "$LINENO" 5 fi CC="$oCC" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for group 'root'" >&5 $as_echo_n "checking for group 'root'... " >&6; } if test "`grep -e ^root: /etc/group`" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no. Using 'wheel'" >&5 $as_echo "no. Using 'wheel'" >&6; } instgrp="wheel" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } instgrp="root" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for group 'man'" >&5 $as_echo_n "checking for group 'man'... " >&6; } if test "`grep -e ^man: /etc/group`" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no. Using '$instgrp'" >&5 $as_echo "no. Using '$instgrp'" >&6; } mangrp="$instgrp" else mangrp="man" fi # Check for libcurses or libncurses. Fatal error if we didn't use disable. # Check whether --enable-client was given. if test "${enable_client+set}" = set; then : enableval=$enable_client; case "${enableval}" in no) wantclient=no ;; *) wantclient=yes ;; esac else wantclient=yes fi # Add additional cflags since some distros bury panel.h CPPFLAGS="$CPPFLAGS -I/usr/include/ncurses" termcontrol="none"; if test "$wantclient" = "yes"; then OLIBS="$LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncurses" >&5 $as_echo_n "checking for initscr in -lncurses... " >&6; } if ${ac_cv_lib_ncurses_initscr+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char initscr (); int main () { return initscr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ncurses_initscr=yes else ac_cv_lib_ncurses_initscr=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_initscr" >&5 $as_echo "$ac_cv_lib_ncurses_initscr" >&6; } if test "x$ac_cv_lib_ncurses_initscr" = xyes; then : $as_echo "#define HAVE_LIBNCURSES 1" >>confdefs.h \ foundlcurses=yes curseaux="-lncurses" termcontrol="ncurses" fi if test "$foundlcurses" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lcurses" >&5 $as_echo_n "checking for initscr in -lcurses... " >&6; } if ${ac_cv_lib_curses_initscr+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char initscr (); int main () { return initscr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_curses_initscr=yes else ac_cv_lib_curses_initscr=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_initscr" >&5 $as_echo "$ac_cv_lib_curses_initscr" >&6; } if test "x$ac_cv_lib_curses_initscr" = xyes; then : $as_echo "#define HAVE_LIBCURSES 1" >>confdefs.h \ foundlcurses=yes curseaux="-lcurses" termcontrol="curses" fi fi if test "$foundlcurses" != "yes"; then as_fn_error $? "Failed to find libcurses or libncurses. Install them or disable building the Kismet client with --disable-client. Disabling the client is probably not something you want to do normally." "$LINENO" 5 fi if test "$termcontrol" = "ncurses"; then ac_fn_c_check_header_mongrel "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default" if test "x$ac_cv_header_ncurses_h" = xyes; then : foundhcurses=yes fi else ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default" if test "x$ac_cv_header_curses_h" = xyes; then : foundhcurses=yes fi fi if test "$foundhcurses" != "yes"; then as_fn_error $? "Failed to find curses.h or ncurses.h. You probably need to install the curses-devel package from your distribution" "$LINENO" 5 fi LIBS="$LIBS $curseaux" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_panel in -lpanel" >&5 $as_echo_n "checking for new_panel in -lpanel... " >&6; } if ${ac_cv_lib_panel_new_panel+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpanel $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char new_panel (); int main () { return new_panel (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_panel_new_panel=yes else ac_cv_lib_panel_new_panel=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panel_new_panel" >&5 $as_echo "$ac_cv_lib_panel_new_panel" >&6; } if test "x$ac_cv_lib_panel_new_panel" = xyes; then : $as_echo "#define HAVE_LIBPANEL 1" >>confdefs.h curseaux="$curseaux -lpanel" else as_fn_error or disable building the Kismet client with --disable-client. Disabling the client is probably not something you want to do normally. "Failed to find libpanel extension to curses/ncurses. Install it" "$LINENO" 5 fi ac_fn_c_check_header_mongrel "$LINENO" "panel.h" "ac_cv_header_panel_h" "$ac_includes_default" if test "x$ac_cv_header_panel_h" = xyes; then : foundhpanel=yes fi if test "$foundhpanel" != "yes"; then as_fn_error $? "Failed to find panel.h curses extension header. You probably need to install the curses-devel or panel-devel package from your distribution." "$LINENO" 5 fi LIBS="$OLIBS" CLIENTCLIBS="$CLIENTCLIBS $curseaux" fi # TODO - check for advanced curses stuff here like cdk/panels # Check for process title manipulation stuff, from proftpd configure.in for ac_func in setproctitle do : ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" if test "x$ac_cv_func_setproctitle" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPROCTITLE 1 _ACEOF fi done for ac_header in libutil.h do : ac_fn_c_check_header_mongrel "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default" if test "x$ac_cv_header_libutil_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBUTIL_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setproctitle in -lutil" >&5 $as_echo_n "checking for setproctitle in -lutil... " >&6; } if ${ac_cv_lib_util_setproctitle+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char setproctitle (); int main () { return setproctitle (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_util_setproctitle=yes else ac_cv_lib_util_setproctitle=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_setproctitle" >&5 $as_echo "$ac_cv_lib_util_setproctitle" >&6; } if test "x$ac_cv_lib_util_setproctitle" = xyes; then : $as_echo "#define HAVE_SETPROCTITLE 1" >>confdefs.h ac_cv_func_setproctitle="yes" ; LIBS="$LIBS -lutil" fi if test "$ac_cv_func_setproctitle" = "yes"; then $as_echo "#define PF_ARGV_TYPE PF_ARGV_NONE" >>confdefs.h else pf_argv_set="no" for ac_header in sys/pstat.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/pstat.h" "ac_cv_header_sys_pstat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_pstat_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PSTAT_H 1 _ACEOF have_pstat_h="yes" else have_pstat_h="no" fi done if test "$have_pstat_h" = "yes"; then for ac_func in pstat do : ac_fn_c_check_func "$LINENO" "pstat" "ac_cv_func_pstat" if test "x$ac_cv_func_pstat" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PSTAT 1 _ACEOF fi done if test "$ac_cv_func_pstat" = "yes"; then $as_echo "#define PF_ARGV_TYPE PF_ARGV_PSTAT" >>confdefs.h else $as_echo "#define PF_ARGV_TYPE PF_ARGV_WRITEABLE" >>confdefs.h fi pf_argv_set="yes" fi if test "$pf_argv_set" = "no"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/exec.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "#define.*PS_STRINGS.*" >/dev/null 2>&1; then : have_psstrings="yes" else have_psstrings="no" fi rm -f conftest* if test "$have_psstrings" = "yes"; then $as_echo "#define PF_ARGV_TYPE PF_ARGV_PSSTRINGS" >>confdefs.h pf_argv_set="yes" fi fi if test "$pf_argv_set" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __progname and __progname_full are available" >&5 $as_echo_n "checking whether __progname and __progname_full are available... " >&6; } if ${pf_cv_var_progname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern char *__progname, *__progname_full; int main () { __progname = "foo"; __progname_full = "foo bar"; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : pf_cv_var_progname="yes" else pf_cv_var_progname="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pf_cv_var_progname" >&5 $as_echo "$pf_cv_var_progname" >&6; } if test "$pf_cv_var_progname" = "yes"; then $as_echo "#define HAVE___PROGNAME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which argv replacement method to use" >&5 $as_echo_n "checking which argv replacement method to use... " >&6; } if ${pf_cv_argv_type+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(__GNU_HURD__) yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : pf_cv_argv_type="new" else pf_cv_argv_type="writeable" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pf_cv_argv_type" >&5 $as_echo "$pf_cv_argv_type" >&6; } if test "$pf_cv_argv_type" = "new"; then $as_echo "#define PF_ARGV_TYPE PF_ARGV_NEW" >>confdefs.h pf_argv_set="yes" fi if test "$pf_argv_set" = "no"; then $as_echo "#define PF_ARGV_TYPE PF_ARGV_WRITEABLE" >>confdefs.h fi fi fi # Check for linux headers if we're on linux systems if test "$linux" = "yes"; then # Check whether --with-linuxheaders was given. if test "${with_linuxheaders+set}" = set; then : withval=$with_linuxheaders; if test "$withval" != no -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval" fi fi # Check whether --enable-linuxwext was given. if test "${enable_linuxwext+set}" = set; then : enableval=$enable_linuxwext; case "${enableval}" in no) wantwext=no ;; *) wantwext=yes ;; esac else wantwext=yes fi linux_wireless="no" if test "$wantwext" = "yes"; then ac_fn_c_check_header_compile "$LINENO" "linux/wireless.h" "ac_cv_header_linux_wireless_h" " #include <sys/types.h> #include <netdb.h> #include <linux/socket.h> #include <asm/types.h> #include <linux/if.h> " if test "x$ac_cv_header_linux_wireless_h" = xyes; then : foundwexth=yes fi if test "$foundwexth" != "yes"; then as_fn_error $? "Failed to find a usable linux/wireless.h header for Linux Wireless Extensions. Either your kernel headers are missing or are incorrect. See config.log for the exact error. Compiling without wireless headers must be explicitly disabled" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking that linux/wireless.h is what we expect" >&5 $as_echo_n "checking that linux/wireless.h is what we expect... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <sys/types.h> #include <netdb.h> #include <netinet/in.h> #include <sys/resource.h> #include <asm/types.h> #include <linux/if.h> #include <linux/wireless.h> int main () { struct iwreq wrq; wrq.u.essid.flags = 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : foundwextok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$foundwextok" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Failed to find a usable linux/wireless.h header for Linux Wireless Extensions. Either your kernel headers are missing or are incorrect. See config.log for the exact error." "$LINENO" 5 fi # wexth { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LINUX_WIRELESS 1" >>confdefs.h linux_wireless="yes"; if test "$linux_wireless" = "yes"; then iwfreqflag=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking can we use iw_freq.flags" >&5 $as_echo_n "checking can we use iw_freq.flags... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <sys/types.h> #include <netinet/in.h> #include <asm/types.h> #include <linux/if.h> #include <linux/wireless.h> int main () { struct iwreq wrq; wrq.u.freq.flags = IW_FREQ_FIXED; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : iwfreqflag=yes else iwfreqflag=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$iwfreqflag" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LINUX_IWFREQFLAG 1" >>confdefs.h fi fi fi # want headers fi # linux # Look for libgps # havelgps="yes" # AC_CHECK_LIB([gps], [gps_open],,havelgps=no) # AC_CHECK_HEADER([gps.h],,havelgps=no) # # if test "$havelgps" = "yes"; then # AC_DEFINE(HAVE_LIBGPS, 1, gpsd libgps client support) # KSLIBS="$KSLIBS -lgps" # fi # Look for capability support havecap="yes" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_init in -lcap" >&5 $as_echo_n "checking for cap_init in -lcap... " >&6; } if ${ac_cv_lib_cap_cap_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cap_init (); int main () { return cap_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_cap_cap_init=yes else ac_cv_lib_cap_cap_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_init" >&5 $as_echo "$ac_cv_lib_cap_cap_init" >&6; } if test "x$ac_cv_lib_cap_cap_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCAP 1 _ACEOF LIBS="-lcap $LIBS" else havecap=no fi ac_fn_c_check_header_mongrel "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_prctl_h" = xyes; then : else havecap=no fi ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default" if test "x$ac_cv_header_sys_capability_h" = xyes; then : else havecap=no fi if test "$havecap" = "yes"; then $as_echo "#define HAVE_CAPABILITY 1" >>confdefs.h caplibs="-lcap" fi # Check whether --with-pcreheaders was given. if test "${with_pcreheaders+set}" = set; then : withval=$with_pcreheaders; if test "$withval" != no -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval" fi fi # Check whether --enable-pcre was given. if test "${enable_pcre+set}" = set; then : enableval=$enable_pcre; case "${enableval}" in no) wantpcre=no ;; *) wantpcre=yes ;; esac else wantpcre=yes fi if test "$wantpcre" = "yes"; then # Check for pcre pcrel=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre" >&5 $as_echo_n "checking for pcre_compile in -lpcre... " >&6; } if ${ac_cv_lib_pcre_pcre_compile+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcre $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcre_compile (); int main () { return pcre_compile (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcre_pcre_compile=yes else ac_cv_lib_pcre_pcre_compile=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_compile" >&5 $as_echo "$ac_cv_lib_pcre_pcre_compile" >&6; } if test "x$ac_cv_lib_pcre_pcre_compile" = xyes; then : pcrel=yes else pcrel=no fi if test "$pcrel" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find libpcre" >&5 $as_echo "$as_me: WARNING: Failed to find libpcre" >&2;} wantpcre=no fi if test "$wantpcre" = "yes"; then pcreh=no ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default" if test "x$ac_cv_header_pcre_h" = xyes; then : pcreh=yes else pcreh=no fi if test "$pcreh" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed to find pcre headers check that the pcre-devel package is installed if your distribution provides separate packages" >&5 $as_echo "$as_me: WARNING: Failed to find pcre headers check that the pcre-devel package is installed if your distribution provides separate packages" >&2;} wantpcre=no fi fi # wantpcre if test "$wantpcre" = "yes"; then $as_echo "#define HAVE_LIBPCRE 1" >>confdefs.h LIBS="$LIBS -lpcre" fi # pcre fi # Handle airpcap/winpcap on cygwin if test "$cygwin" = yes; then for ac_header in windows.h Win32-Extensions.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Check whether --enable-airpcap was given. if test "${enable_airpcap+set}" = set; then : enableval=$enable_airpcap; case "${enableval}" in yes) want_airpcap=yes ;; *) want_airpcap=no ;; esac else want_airpcap=yes fi if test "$want_airpcap" = "yes"; then airpcap_devpack="Airpcap_Devpack" # Check whether --with-airpcap-devpack was given. if test "${with_airpcap_devpack+set}" = set; then : withval=$with_airpcap_devpack; airpcap_devpack="$withval" fi # Set the libs and includes LDFLAGS="$LDFLAGS -L$airpcap_devpack/Lib" CPPFLAGS="$CPPFLAGS -I$airpcap_devpack/Include" fi # want_airpcap winpcap_devpack="Winpcap_Devpack" # Check whether --with-winpcap-devpack was given. if test "${with_winpcap_devpack+set}" = set; then : withval=$with_winpcap_devpack; winpcap_devpack="$withval" fi # Set the libs and includes LDFLAGS="$LDFLAGS -L$winpcap_devpack/Lib" CPPFLAGS="$CPPFLAGS -I$winpcap_devpack/Include" fi # cygwin # Check whether --enable-pcap was given. if test "${enable_pcap+set}" = set; then : enableval=$enable_pcap; case "${enableval}" in no) wantpcap=no ;; *) wantpcap=yes ;; esac else wantpcap=yes fi if test "$wantpcap" = yes; then foundsyspcap=no if test "$cygwin" = yes; then pcaplib="wpcap"; else pcaplib="pcap"; fi as_ac_Lib=`$as_echo "ac_cv_lib_${pcaplib}''_pcap_open_live" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -l${pcaplib}" >&5 $as_echo_n "checking for pcap_open_live in -l${pcaplib}... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-l${pcaplib} $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_open_live (); int main () { return pcap_open_live (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : $as_echo "#define HAVE_LIBPCAP 1" >>confdefs.h foundsyspcap=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling without libpcap support." >&5 $as_echo "$as_me: WARNING: Compiling without libpcap support." >&2;} fi if test "$foundsyspcap" = yes; then ## if we don't have a pcap.h, do a search for pcap/pcap.h ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default" if test "x$ac_cv_header_pcap_h" = xyes; then : $as_echo "#define HAVE_PCAP_H 1" >>confdefs.h foundsyspcaph=yes fi if test "$foundsyspcaph" != yes; then ac_fn_c_check_header_mongrel "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default" if test "x$ac_cv_header_pcap_pcap_h" = xyes; then : $as_echo "#define HAVE_PCAP_H 1" >>confdefs.h $as_echo "#define HAVE_PCAPPCAP_H 1" >>confdefs.h else as_fn_error $? "found libpcap but unable to find pcap.h" "$LINENO" 5 fi fi # Look for the new PCAP stuff { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_setnonblock in -lpcap" >&5 $as_echo_n "checking for pcap_setnonblock in -lpcap... " >&6; } if ${ac_cv_lib_pcap_pcap_setnonblock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_setnonblock (); int main () { return pcap_setnonblock (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcap_pcap_setnonblock=yes else ac_cv_lib_pcap_pcap_setnonblock=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_setnonblock" >&5 $as_echo "$ac_cv_lib_pcap_pcap_setnonblock" >&6; } if test "x$ac_cv_lib_pcap_pcap_setnonblock" = xyes; then : $as_echo "#define HAVE_PCAP_NONBLOCK 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** You don't appear to have a version of libpcap which supports non-blocking IO. We'll fake it" >&5 $as_echo "$as_me: WARNING: *** You don't appear to have a version of libpcap which supports non-blocking IO. We'll fake it" >&2;} fi if test "$cygwin" != yes; then as_ac_Lib=`$as_echo "ac_cv_lib_${pcaplib}''_pcap_get_selectable_fd" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_get_selectable_fd in -l${pcaplib}" >&5 $as_echo_n "checking for pcap_get_selectable_fd in -l${pcaplib}... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-l${pcaplib} $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_get_selectable_fd (); int main () { return pcap_get_selectable_fd (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : $as_echo "#define HAVE_PCAP_GETSELFD 1" >>confdefs.h else as_fn_error $? "installed libpcap version does not support features Kismet requires. Upgrade to a current version of libpcap" "$LINENO" 5 fi else as_ac_Lib=`$as_echo "ac_cv_lib_${pcaplib}''_pcap_fileno" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_fileno in -l${pcaplib}" >&5 $as_echo_n "checking for pcap_fileno in -l${pcaplib}... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-l${pcaplib} $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_fileno (); int main () { return pcap_fileno (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : $as_echo "#define HAVE_PCAP_FILENO 1" >>confdefs.h else as_fn_error $? "installed libpcap version does not support features Kismet requires. Upgrade to a current version of libwpcap" "$LINENO" 5 fi fi # Look for PPI support in pcap { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PPI support in libpcap" >&5 $as_echo_n "checking for PPI support in libpcap... " >&6; } OCFL="$CFLAGS" CFLAGS="-Werror $CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <pcap.h> int main () { return DLT_PPI==DLT_PPI; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : haveppi=yes else haveppi=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$OCFL" if test "$haveppi" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_PPI 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi pcaplnk="-l${pcaplib}" pcap="yes" fi fi if test "$wantpcap" = "yes" -a "$pcap" != "yes"; then as_fn_error $? "Could not find working libpcap. Libpcap is vital for the majority of capture sources Kismet supports. It must be explicitly disabled." "$LINENO" 5 fi if test "$wantpcap" != "yes" -o "$pcap" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling without libpcap support. Many capture sources will be disabled." >&5 $as_echo "$as_me: WARNING: Compiling without libpcap support. Many capture sources will be disabled." >&2;} fi if test "$pcap" = "no" -a "$want_airpcap" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Disabling AirPcap, libpcap not enabled ***" >&5 $as_echo "$as_me: WARNING: *** Disabling AirPcap, libpcap not enabled ***" >&2;}; want_airpcap=no; fi if test "$want_airpcap" = "yes" -a "$pcap" = "yes"; then foundairpcap=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AirpcapSetLinkType in -lairpcap" >&5 $as_echo_n "checking for AirpcapSetLinkType in -lairpcap... " >&6; } if ${ac_cv_lib_airpcap_AirpcapSetLinkType+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lairpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char AirpcapSetLinkType (); int main () { return AirpcapSetLinkType (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_airpcap_AirpcapSetLinkType=yes else ac_cv_lib_airpcap_AirpcapSetLinkType=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_airpcap_AirpcapSetLinkType" >&5 $as_echo "$ac_cv_lib_airpcap_AirpcapSetLinkType" >&6; } if test "x$ac_cv_lib_airpcap_AirpcapSetLinkType" = xyes; then : $as_echo "#define HAVE_LIBAIRPCAP 1" >>confdefs.h foundairpcap=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling without airpcap support." >&5 $as_echo "$as_me: WARNING: Compiling without airpcap support." >&2;} fi if test "$foundairpcap" = yes; then ## if we don't have a pcap.h, do a search for pcap/pcap.h ac_fn_c_check_header_mongrel "$LINENO" "airpcap.h" "ac_cv_header_airpcap_h" "$ac_includes_default" if test "x$ac_cv_header_airpcap_h" = xyes; then : $as_echo "#define HAVE_AIRPCAP_H 1" >>confdefs.h foundairpcaph=yes fi fi if test "$foundairpcap" != "yes" -o "$foundairpcaph" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling without airpcap support" >&5 $as_echo "$as_me: WARNING: Compiling without airpcap support" >&2;} else airpcap="yes" KSLIBS="$KSLIBS -lairpcap" fi fi if test "$bsd" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD net80211/radiotap support" >&5 $as_echo_n "checking for BSD net80211/radiotap support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_media.h> #include <net80211/ieee80211_radiotap.h> int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : radiotap=yes bsdradiotap=yes else bsdradiotap=no radiotap=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bsdradiotap" >&5 $as_echo "$bsdradiotap" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Using local radiotap headers" >&5 $as_echo "$as_me: WARNING: Using local radiotap headers" >&2;} fi if test "$radiotap" != "yes"; then $as_echo "#define HAVE_LOCAL_RADIOTAP 1" >>confdefs.h radiotaploc="local" fi if test "$bsdradiotap" = "yes"; then $as_echo "#define HAVE_BSD_SYS_RADIOTAP 1" >>confdefs.h radiotaploc="system (BSD)" fi # havenetlink=no if test "$linux" = "yes"; then # havenetlink=yes # AC_CHECK_HEADERS([asm/types.h netlink/genl/genl.h netlink/genl/family.h netlink/genl/ctrl.h netlink/msg.h netlink/attr.h linux/nl80211.h linux/if_arp.h linux/wireless.h], # AC_DEFINE(HAVE_NETLINKHEADERS, 1, Netlink headers are there), # havenetlink=no, # [#include <sys/socket.h>]) havenetlink=yes #if test "$havenetlink" = "yes"; then # AC_CHECK_LIB([nl], [nl_handle_alloc], # AC_DEFINE(HAVE_LIBNL, 1, libnl netlink library), havenetlink=no) #else # AC_MSG_WARN(Missing libnl or libnl too old support will not be able to control mac80211 vaps) #fi netlink_force=no # Check whether --with-netlink-version was given. if test "${with_netlink_version+set}" = set; then : withval=$with_netlink_version; netlink_force=$withval fi # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_havepkgconfig+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$havepkgconfig"; then ac_cv_prog_havepkgconfig="$havepkgconfig" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_havepkgconfig="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_havepkgconfig" && ac_cv_prog_havepkgconfig="no" fi fi havepkgconfig=$ac_cv_prog_havepkgconfig if test -n "$havepkgconfig"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $havepkgconfig" >&5 $as_echo "$havepkgconfig" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$havepkgconfig" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Missing pkg-config will lead to multiple other checks failing" >&5 $as_echo "$as_me: WARNING: Missing pkg-config will lead to multiple other checks failing" >&2;} fi NLLIBS="" NLCFLAGS="" nlname="" if test "$havenetlink" = "yes"; then if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl30" >&5 $as_echo_n "checking for libnl30... " >&6; } if test -n "$libnl30_CFLAGS"; then pkg_cv_libnl30_CFLAGS="$libnl30_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl30_CFLAGS=`$PKG_CONFIG --cflags "libnl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libnl30_LIBS"; then pkg_cv_libnl30_LIBS="$libnl30_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl30_LIBS=`$PKG_CONFIG --libs "libnl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libnl30_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnl-3.0" 2>&1` else libnl30_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnl-3.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libnl30_PKG_ERRORS" >&5 libnl30=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libnl30=no else libnl30_CFLAGS=$pkg_cv_libnl30_CFLAGS libnl30_LIBS=$pkg_cv_libnl30_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libnl30=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnlgenl30" >&5 $as_echo_n "checking for libnlgenl30... " >&6; } if test -n "$libnlgenl30_CFLAGS"; then pkg_cv_libnlgenl30_CFLAGS="$libnlgenl30_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnlgenl30_CFLAGS=`$PKG_CONFIG --cflags "libnl-genl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libnlgenl30_LIBS"; then pkg_cv_libnlgenl30_LIBS="$libnlgenl30_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnlgenl30_LIBS=`$PKG_CONFIG --libs "libnl-genl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libnlgenl30_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnl-genl-3.0" 2>&1` else libnlgenl30_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnl-genl-3.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libnlgenl30_PKG_ERRORS" >&5 libnlgenl30=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libnlgenl30=no else libnlgenl30_CFLAGS=$pkg_cv_libnlgenl30_CFLAGS libnlgenl30_LIBS=$pkg_cv_libnlgenl30_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libnlgenl30=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl20" >&5 $as_echo_n "checking for libnl20... " >&6; } if test -n "$libnl20_CFLAGS"; then pkg_cv_libnl20_CFLAGS="$libnl20_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl20_CFLAGS=`$PKG_CONFIG --cflags "libnl-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libnl20_LIBS"; then pkg_cv_libnl20_LIBS="$libnl20_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl20_LIBS=`$PKG_CONFIG --libs "libnl-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libnl20_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnl-2.0" 2>&1` else libnl20_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnl-2.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libnl20_PKG_ERRORS" >&5 libnl20=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libnl20=no else libnl20_CFLAGS=$pkg_cv_libnl20_CFLAGS libnl20_LIBS=$pkg_cv_libnl20_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libnl20=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl1" >&5 $as_echo_n "checking for libnl1... " >&6; } if test -n "$libnl1_CFLAGS"; then pkg_cv_libnl1_CFLAGS="$libnl1_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl1_CFLAGS=`$PKG_CONFIG --cflags "libnl-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libnl1_LIBS"; then pkg_cv_libnl1_LIBS="$libnl1_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libnl1_LIBS=`$PKG_CONFIG --libs "libnl-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libnl1_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnl-1" 2>&1` else libnl1_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnl-1" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libnl1_PKG_ERRORS" >&5 libnl1=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libnl1=no else libnl1_CFLAGS=$pkg_cv_libnl1_CFLAGS libnl1_LIBS=$pkg_cv_libnl1_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libnl1=yes fi picked_nl=no if test $picked_nl = "no" -a "$libnl30" = "yes" -a "$libnlgenl30" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "3"; then picked_nl=3 $as_echo "#define HAVE_LIBNL 1" >>confdefs.h $as_echo "#define HAVE_LIBNL30 1" >>confdefs.h nlname="libnl-3.0 libnl-genl-3.0" fi fi if test $picked_nl = "no" -a "$libnl20" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "2"; then picked_nl=2 $as_echo "#define HAVE_LIBNL 1" >>confdefs.h $as_echo "#define HAVE_LIBNL20 1" >>confdefs.h nlname="libnl-2.0" fi fi if test $picked_nl = "no" -a "$libnl1" = "yes"; then if test $netlink_force = "no" -o $netlink_force = "1"; then picked_nl=1 $as_echo "#define HAVE_LIBNL 1" >>confdefs.h nlname="libnl-1" fi fi if test $picked_nl = "no"; then havenetlink="no" fi if test "$nlname" != ""; then NLLIBS=`pkg-config --libs $nlname` NLCFLAGS=`pkg-config --cflags $nlname` fi fi if test "$havenetlink" = "yes"; then OLIBS="$LIBS" LIBS="$LIBS $NLLIBS" OCFL="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $NLCFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking For mac80211 support in netlink library" >&5 $as_echo_n "checking For mac80211 support in netlink library... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> #include <asm/types.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> #include <netlink/genl/ctrl.h> #include <netlink/msg.h> #include <netlink/attr.h> #include <linux/nl80211.h> #include <linux/if_arp.h> #include <linux/wireless.h> int main () { NL80211_IFTYPE_MONITOR; NL80211_CMD_NEW_INTERFACE; return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : havenetlink=yes KSLIBS="$KSLIBS $NLLIBS" else havenetlink=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$OLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Missing libnl netlink library will not be able to control mac80211 vaps" >&5 $as_echo "$as_me: WARNING: Missing libnl netlink library will not be able to control mac80211 vaps" >&2;} havenetlink=no fi if test "$havenetlink" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LINUX_NETLINK 1" >>confdefs.h fi fi if test "$darwin" = "yes"; then suidgroup="staff" else suidgroup="kismet" fi # Check whether --with-suidgroup was given. if test "${with_suidgroup+set}" = set; then : withval=$with_suidgroup; if test "$withval"x != "x"; then suidgroup="$withval" fi fi # Evaluate suid if test "$cygwin" = "yes"; then suid="no" fi # gpsmap checks # We include GPS handling code regardless, for now. $as_echo "#define HAVE_GPS 1" >>confdefs.h # Check whether --enable-optimization was given. if test "${enable_optimization+set}" = set; then : enableval=$enable_optimization; case "${enableval}" in no) wantopto=no ;; *) wantopto=yes ;; esac else wantopto=yes fi if test "$wantopto" != "yes"; then CPPFLAGS=`echo $CPPFLAGS | sed -e 's/-O.//g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-O.//g'` fi sharedatadir=$datadir sharedatadir=`( test "$prefix" = NONE && prefix=$ac_default_prefix test "$exec_prefix" = NONE && exec_prefix=${prefix} eval echo "$sharedatadir" )` sharedatadir=${sharedatadir} ac_config_files="$ac_config_files Makefile Makefile.inc scripts/kismet conf/kismet.conf" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile.inc") CONFIG_FILES="$CONFIG_FILES Makefile.inc" ;; "scripts/kismet") CONFIG_FILES="$CONFIG_FILES scripts/kismet" ;; "conf/kismet.conf") CONFIG_FILES="$CONFIG_FILES conf/kismet.conf" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' <conf$$subs.awk | sed ' /^[^""]/{ N s/\n// } ' >>$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' <confdefs.h | sed ' s/'"$ac_delim"'/"\\\ "/g' >>$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo echo "Configuration complete: " echo " Compiling for: $host_os ($host_cpu)" echo " C++ Library: $foundcxxl" echo " Installing as group: $instgrp" echo " Man pages owned by: $mangrp" echo " Installing into: $prefix" printf " Setuid group: " if test "$cygwin" = "yes"; then echo "n/a (Cygwin/Win32"; else echo "$suidgroup" fi printf " Terminal Control: " echo "$termcontrol"; printf " Linux WEXT capture : " if test "$linux_wireless" = "yes"; then echo "yes" elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no" fi printf " OSX/Darwin capture : " if test "$darwin" = "yes"; then echo "yes" elif test "$darwin" != "yes"; then echo "n/a (only OSX/Darwin)" else echo "no" fi printf " PCRE Regex Filters : " if test "$wantpcre" = "yes"; then echo "yes" else echo "no" fi printf " pcap capture: " if test "$pcap" = "yes"; then echo "yes" else echo "no" fi printf " airpcap control: " if test "$airpcap" = "yes"; then echo "yes" elif test "$cygwin" != "yes"; then echo "n/a (only Cygwin/Win32)" else echo "no" fi printf " PPI log format: " if test "$haveppi" = "yes"; then echo "yes" else echo "no - PPI logging unavailable, upgrade libpcap" fi printf "LibCapability (enhanced\n" printf " privilege dropping): " if test "$havecap" = "yes"; then echo "yes"; elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no"; fi printf " Linux Netlink: " if test "$havenetlink" = "yes"; then echo "yes (mac80211 VAP creation) - $nlname"; elif test "$linux" != "yes"; then echo "n/a (only Linux)" else echo "no (will not be able to make mac80211 vaps)"; fi # printf " GPSD LibGPS: " # if test "$havelgps" = "yes"; then # echo "yes (GPSD LibGPS client)"; # else # echo "no (Using Kismet GPSD interface for GPSD <= 2.90)"; # fi if test "$havepkgconfig" = "no"; then echo echo "pkg-config was missing. Without it, configure cannot detect " echo "several libraries Kismet needs. Install pkg-config and re-run" echo "configure." fi if test "`echo $host_os | grep linux`" = ""; then echo echo "Configuration complete. You are not running a linux-based system," echo "you will likely need to use 'gmake' instead of 'make'." echo "Run 'gmake dep' to generate dependencies and 'gmake' followed by" echo "'gmake install' to compile and install Kismet" else verminor=`uname -r | cut -d '.' -f 2` # Stupid redhat vertiny=`uname -r | cut -d '.' -f 3 | cut -f 1 -d-` echo echo "Configuration complete. Run 'make dep' to generate dependencies" echo "and 'make' followed by 'make install' to compile and install." fi if test "$linux_wireless" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "Linux Wireless Extensions were disabled. Compiling without wext on a " echo "Linux system is certainly possible, however nearly all of the packet " echo "sources will be disabled (including capture sources for Cisco, Madwifi, " echo "Orinoco, Prism, and just about every other live capture method). Make " echo "sure this is what you want to do." echo "*** WARNING ***" fi if test "$pcap" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "LibPCAP was not found." echo "Kismet on Linux without LibPcap cannot capture data locally and will " echo "almost certainly NOT BE WHAT YOU WANT." echo "You need both the libpcap libraries and development headers (called " echo "libpcap-dev or libpcap-devel by most distributions)." fi if test "$havenetlink" != "yes" -a "$linux" = "yes"; then echo echo "*** WARNING ***" echo "LibNL/nl80211 support was not found. Kismet uses libnl to control " echo "mac80211 based wireless interfaces, which comprise the vast majority of" echo "interfaces on modern Linux systems. Unless you plan to use only " echo "older drivers, you need libnl." echo "You need both the libnl libraries and development headers (called " echo "libnl-dev or libnl-devel by most distributions)." if test "$havepkgconfig" = "no"; then echo "You do not have the pkg-config utility installed. Kismet needs " echo "this to find the options libnl uses. If libnl is installed but " echo "pkg-config is not, Kismet will not detect libnl!" fi fi if test "$havenetlink" = "yes" -a "$pcap" = "yes"; then echo echo "*** WARNING ***" echo "In some situations, libpcap links to libnl. If Kismet finds a newer " echo "libbl, it can cause an immediate segfault when starting Kismet. " echo echo "It is very hard to test at compile time (and run-time changes can " echo "cause it to break). If you experience immediate segfaults when " echo "trying to start kismet_server, check your libpcap.so with 'ldd'" echo "and either install a libpcap which does not link libnl1, or " echo "force Kismet to compile with a degraded libnl via " echo "./configure --with-netlink-version=1" echo fi ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/packetsignatures.h���������������������������������������������������������������0000664�0001750�0001750�00000010663�12124602454�017206� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSIGNATURES_H__ #define __PACKETSIGNATURES_H__ #include "config.h" #ifdef HAVE_STDINT #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif const uint8_t LOR_MAC[] = {0x01, 0x00, 0x00, 0x00, 0x20, 0xF6}; const uint8_t NUL_MAC[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const uint8_t NETS_MAC[] = {0x01, 0x60, 0x1d, 0x00, 0x01, 0x00}; // LLC packets with control field U func UI (we handle a lot of things with these headers) const uint8_t LLC_UI_SIGNATURE[] = {0xAA, 0xAA, 0x03}; // Offset for the start of the LLC frame const unsigned int LLC_OFFSET = 0; // Offset for all LLC-fragment protocols const unsigned int LLC_UI_OFFSET = 3; // LLC packets that look like probe info (netstumbler and lucent) const uint8_t PROBE_LLC_SIGNATURE[] = {0x00, 0x60, 0x1D}; // "All" is all we need to match at this offset. We matched the LLC already so // we can use a very small fragment // This catches "All your 802.11b are belong to us" const uint8_t NETSTUMBLER_323_SIGNATURE[] = {0x41, 0x6C, 0x6C}; // "Flu" again is all we need to match at this offset. // This catches "Flurble gronk bloopit, bnip Frundletrune" const uint8_t NETSTUMBLER_322_SIGNATURE[] = {0x46, 0x6C, 0x75}; // " " is the beginning of the .30 // " Intentionally blank" const uint8_t NETSTUMBLER_330_SIGNATURE[] = {0x20, 0x20, 0x20}; const uint8_t NETSTUMBLER_OFFSET = 12; // Lucent link test signatures const uint8_t LUCENT_TEST_SIGNATURE[] = {0x00, 0x01, 0x02, 0x03}; const uint8_t LUCENT_OFFSET = 12; const uint8_t CISCO_SIGNATURE[] = {0x00, 0x00, 0x0C, 0x20, 0x00}; const unsigned int CDP_ELEMENT_LEN = 5; const uint8_t FORTRESS_SIGNATURE[] = {0x00, 0x00, 0x00, 0x88, 0x95}; // WPA/WPA2 identifiers const uint8_t WPA_OUI[] = {0x00, 0x50, 0xF2}; const uint8_t RSN_OUI[] = {0x00, 0x0F, 0xAC}; const uint8_t DOT1X_PROTO[] = {0x88, 0x8e}; const uint8_t DOT1X_OFFSET = LLC_UI_OFFSET + 5; const uint8_t DOT1X_HEADER_SIZE = 4; const uint8_t EAP_OFFSET = 4; const uint8_t EAP_PACKET_SIZE = 5; const uint8_t EAP_CODE_REQUEST = 1; const uint8_t EAP_CODE_RESPONSE = 2; const uint8_t EAP_CODE_SUCCESS = 3; const uint8_t EAP_CODE_FAILURE = 4; const uint8_t EAP_TYPE_TLS = 13; const uint8_t EAP_TYPE_LEAP = 17; const uint8_t EAP_TYPE_TTLS = 21; const uint8_t EAP_TYPE_PEAP = 25; const uint8_t ARP_SIGNATURE[] = {0x08, 0x06}; const unsigned int ARP_OFFSET = 6; const uint8_t ARP_PACKET_SIZE = 30; const uint8_t DHCPD_SIGNATURE[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x43, 0x00, 0x44}; const unsigned int DHCPD_OFFSET = 24; const unsigned int IP_OFFSET = 17; const uint8_t IP_HEADER_SIZE = 11; const uint8_t UDP_SIGNATURE[] = {0x11}; const unsigned int UDP_OFFSET = 28; const uint8_t TCP_SIGNATURE[] = {0x06}; const unsigned int TCP_OFFSET = 28; const unsigned int TCP_HEADER_SIZE = 11; const uint8_t NETBIOS_TCP_OFFSET = 204; const uint8_t NETBIOS_OFFSET = 133; // netbios LLC signature const uint8_t NETBIOS_SIGNATURE[] = {0xF0, 0xF0, 0x03}; // IPX LLC signature const uint8_t IPX_SIGNATURE[] = {0xE0, 0xE0, 0x03}; // IAPP const unsigned int IAPP_OFFSET = 36; const uint8_t IAPP_HEADER_SIZE = 2; const uint8_t IAPP_PDUHEADER_SIZE = 3; const uint16_t IAPP_PORT = 2313; const uint16_t ISAKMP_PORT = 500; const uint8_t ISAKMP_OFFSET = UDP_OFFSET + 8; const unsigned int ISAKMP_PACKET_SIZE = 14; const uint8_t ISAKMP_EXCH_NONE = 0; const uint8_t ISAKMP_EXCH_BASE = 1; const uint8_t ISAKMP_EXCH_IDPROT = 2; const uint8_t ISAKMP_EXCH_AUTHONLY = 3; const uint8_t ISAKMP_EXCH_AGGRESS = 4; const uint8_t ISAKMP_EXCH_INFORM = 5; const uint8_t ISAKMP_EXCH_TRANS = 6; const uint8_t ISAKMP_EXCH_QUICK = 32; const uint8_t ISAKMP_EXCH_NEWGRP = 33; // PPTP const uint16_t PPTP_PORT = 1723; const mac_addr msfopcode_mac = mac_addr("90:E9:75:00:00:00/FF:FF:FF:00:00:00"); #endif �����������������������������������������������������������������������������kismet-2013-03-R1b/ifcontrol.cc���������������������������������������������������������������������0000664�0001750�0001750�00000020620�12124602454�015761� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "ifcontrol.h" #ifdef SYS_LINUX #include <netdb.h> #endif #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <strings.h> int Ifconfig_Set_Flags(const char *in_dev, char *errstr, int flags) { #ifndef SYS_CYGWIN struct ifreq ifr; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "SetIFFlags: Failed to create AF_INET " "DGRAM socket. %d:%s", errno, strerror(errno)); return errno; } // Fetch interface flags memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, in_dev, sizeof(ifr.ifr_name)-1); #if defined(SYS_FREEBSD) ifr.ifr_flags = flags & 0xFFFF; ifr.ifr_flagshigh = flags >> 16; #else ifr.ifr_flags = flags; #endif if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "SetIFFlags: interface %s: %s", in_dev, strerror(errno)); close(skfd); return errno; } close(skfd); #endif return 0; } int Ifconfig_Get_Flags(const char *in_dev, char *errstr, int *flags) { #ifndef SYS_CYGWIN struct ifreq ifr; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "GetIFFlags: Failed to create AF_INET " "DGRAM socket. %d:%s", errno, strerror(errno)); return -1; } // Fetch interface flags memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, in_dev, sizeof(ifr.ifr_name)-1); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "GetIFFlags: interface %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } #if defined(SYS_FREEBSD) (*flags) = (ifr.ifr_flags & 0xFFFF) | (ifr.ifr_flagshigh << 16); #else (*flags) = ifr.ifr_flags; #endif close(skfd); #endif return 0; } int Ifconfig_Delta_Flags(const char *in_dev, char *errstr, int flags) { #ifndef SYS_CYGWIN int ret; int rflags; if ((ret = Ifconfig_Get_Flags(in_dev, errstr, &rflags)) < 0) return ret; rflags |= flags; return Ifconfig_Set_Flags(in_dev, errstr, rflags); #endif return 0; } #ifdef SYS_LINUX int Linux_GetDrvInfo(const char *in_dev, char *errstr, struct ethtool_drvinfo *info) { struct ifreq ifr; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Failed to create ioctl socket to get " "driver info on %s: %s", in_dev, strerror(errno)); return -1; } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); info->cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t) info; if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Failed to get driver info on %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } string Linux_GetSysDrv(const char *in_dev) { char devlinktarget[512]; ssize_t devlinklen; string devlink = "/sys/class/net/" + string(in_dev) + "/device/driver"; char *rind = NULL; devlinklen = readlink(devlink.c_str(), devlinktarget, 511); if (devlinklen > 0) { devlinktarget[devlinklen] = '\0'; rind = rindex(devlinktarget, '/'); // If we found it and not at the end of the line if (rind != NULL && (rind - devlinktarget) + 1 < devlinklen) return string(rind + 1); } return ""; } int Linux_GetSysDrvAttr(const char *in_dev, const char *attr) { char devlink[256]; struct stat buf; snprintf(devlink, 256, "/sys/class/net/%s/%s", in_dev, attr); if (stat(devlink, &buf) != 0) return 0; return 1; } int Ifconfig_Get_Hwaddr(const char *in_dev, char *errstr, uint8_t *ret_hwaddr) { struct ifreq ifr; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Getting HWAddr: failed to create AF_INET " "DGRAM socket. %s", strerror(errno)); return -1; } // Fetch interface flags strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Getting HWAddr: interface %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } memcpy(ret_hwaddr, ifr.ifr_hwaddr.sa_data, 6); close(skfd); return 0; } int Ifconfig_Set_Hwaddr(const char *in_dev, char *errstr, uint8_t *in_hwaddr) { struct ifreq ifr; int skfd; // struct sockaddr sa; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Setting HWAddr: failed to create AF_INET " "DGRAM socket. %s", strerror(errno)); return errno; } strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); memcpy(ifr.ifr_hwaddr.sa_data, in_hwaddr, 6); ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; // memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Setting HWAddr: interface %s: %s", in_dev, strerror(errno)); close(skfd); return errno; } close(skfd); return 0; } int Ifconfig_Set_MTU(const char *in_dev, char *errstr, uint16_t in_mtu) { struct ifreq ifr; int skfd; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Setting MTU: failed to create AF_INET " "DGRAM socket. %s", strerror(errno)); return -1; } strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); ifr.ifr_mtu = in_mtu; if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Setting MTU: interface %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } int Ifconfig_Set_IP(const char *in_dev, char *errstr, const char *ip) { struct ifreq ifr; int skfd; struct sockaddr_in sin; struct hostent *hp; sin.sin_family = AF_INET; sin.sin_port = 0; if ((hp = gethostbyname(ip)) != NULL) { memcpy(&(sin.sin_addr), hp->h_addr_list[0], sizeof(struct in_addr)); } else { snprintf(errstr, STATUS_MAX, "Setting IPAddr: unable to resolve address %s", ip); return -1; } if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Setting IPAddr: failed to create AF_INET " "DGRAM socket. %s", strerror(errno)); return -1; } strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); memcpy(&(ifr.ifr_addr), &sin, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCSIFADDR, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Setting IPAddr failed %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } int Ifconfig_Set_Netmask(const char *in_dev, char *errstr, const char *netmask) { struct ifreq ifr; int skfd; struct sockaddr_in sin; struct hostent *hp; sin.sin_family = AF_INET; sin.sin_port = 0; if ((hp = gethostbyname(netmask)) != NULL) { memcpy(&(sin.sin_addr), hp->h_addr_list[0], sizeof(struct in_addr)); } else { snprintf(errstr, STATUS_MAX, "Setting netmask: unable to resolve address %s", netmask); return -1; } if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { snprintf(errstr, STATUS_MAX, "Setting netmask: failed to create AF_INET " "DGRAM socket. %s", strerror(errno)); return -1; } strncpy(ifr.ifr_name, in_dev, IFNAMSIZ); memcpy(&(ifr.ifr_addr), &sin, sizeof(struct sockaddr)); if (ioctl(skfd, SIOCSIFNETMASK, &ifr) < 0) { snprintf(errstr, STATUS_MAX, "Setting netmask failed %s: %s", in_dev, strerror(errno)); close(skfd); return -1; } close(skfd); return 0; } #endif ����������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/packetsource_drone.cc������������������������������������������������������������0000664�0001750�0001750�00000073550�12124602454�017653� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <string> #include <sstream> #include "endian_magic.h" #include "packet.h" #include "packetsource.h" #include "packetchain.h" #include "gpscore.h" #include "kis_droneframe.h" #include "clinetframework.h" #include "tcpclient.h" #include "packetsourcetracker.h" #include "packetsource_drone.h" int droneclienttimer_hook(TIMEEVENT_PARMS) { return ((DroneClientFrame *) parm)->time_handler(); } void droneclient_pst_sourceact_hook(SOURCEACT_PARMS) { ((DroneClientFrame *) auxptr)->SourceActionHandler(src, action, flags); } DroneClientFrame::DroneClientFrame() { fprintf(stderr, "FATAL OOPS: DroneClientFrame called without globalreg\n"); exit(1); } DroneClientFrame::DroneClientFrame(GlobalRegistry *in_globalreg) : ClientFramework(in_globalreg) { // Not much to do here, the real magic happens in OpenConnection(..) globalreg = in_globalreg; if (globalreg->packetchain == NULL) { fprintf(stderr, "FATAL OOPS: DroneClientFrame called before packetchain\n"); exit(1); } if (globalreg->timetracker == NULL) { fprintf(stderr, "FATAL OOPS: DroneClientFrame called before timetracker\n"); exit(1); } if (globalreg->sourcetracker == NULL) { fprintf(stderr, "FATAL OOPS: DroneClientFrame called before sourcetracker\n"); exit(1); } netclient = NULL; tcpcli = NULL; packetsource = NULL; reconnect = 0; cli_type = -1; timerid = globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC, NULL, 1, &droneclienttimer_hook, (void *) this); // Catch channel set stuff here globalreg->sourcetracker->RegisterSourceActCallback(&droneclient_pst_sourceact_hook, (void *) this); last_disconnect = 0; last_frame = 0; // globalreg->RegisterPollableSubsys(this); } DroneClientFrame::~DroneClientFrame() { if (netclient != NULL) { netclient->KillConnection(); } if (timerid >= 0 && globalreg != NULL) { globalreg->timetracker->RemoveTimer(timerid); } globalreg->sourcetracker->RemoveSourceActCallback(&droneclient_pst_sourceact_hook); globalreg->RemovePollableSubsys(this); } void DroneClientFrame::SetPacketsource(void *in_src) { packetsource = in_src; } void dcf_connect_hook(GlobalRegistry *globalreg, int status, void *auxptr) { ((DroneClientFrame *) auxptr)->ConnectCB(status); } void DroneClientFrame::ConnectCB(int status) { ostringstream osstr; // fprintf(stderr, "debug - dcf connectcb %u\n", status); if (status != 0) { if (reconnect == 0) { osstr << "Kismet drone connection to " << cli_host << ":" << cli_port << " failed (" << strerror(errno) << ") and reconnection " "not enabled"; _MSG(osstr.str(), MSGFLAG_PRINTERROR); return; } else { osstr << "Could not create connection to the Kismet drone " "server at " << cli_host << ":" << cli_port << " (" << strerror(errno) << "), will attempt to reconnect in 5 seconds"; _MSG(osstr.str(), MSGFLAG_PRINTERROR); } last_disconnect = globalreg->timestamp.tv_sec; last_frame = globalreg->timestamp.tv_sec; return; } last_disconnect = 0; last_frame = globalreg->timestamp.tv_sec; return; } int DroneClientFrame::OpenConnection(string in_conparm, int in_recon) { char cli_proto[11]; ostringstream osstr; // fprintf(stderr, "debug - dcf openconnection\n"); if (sscanf(in_conparm.c_str(), "%10[^:]://%128[^:]:%d", cli_proto, cli_host, &cli_port) != 3) { _MSG("Drone client unable to parse remote server info from '" + in_conparm + "', expected proto://host:port", MSGFLAG_PRINTERROR); return -1; } if (strncasecmp(cli_proto, "tcp", 10) == 0) { tcpcli = new TcpClient(globalreg); netclient = tcpcli; RegisterNetworkClient(tcpcli); tcpcli->RegisterClientFramework(this); cli_type = 0; } else { _MSG("Invalid protocol '" + string(cli_proto) + "' for drone connection", MSGFLAG_PRINTERROR); return -1; } last_frame = globalreg->timestamp.tv_sec; reconnect = in_recon; // Queue async reconnect netclient->Connect(cli_host, cli_port, dcf_connect_hook, this); return 1; } int DroneClientFrame::time_handler() { if (last_disconnect != 0) { if (globalreg->timestamp.tv_sec - last_disconnect > 5) { _MSG("Attempting to reconnect to Kismet drone server at " + string(cli_host) + ":" + IntToString(cli_port), MSGFLAG_ERROR); last_frame = globalreg->timestamp.tv_sec; Reconnect(); } } if (last_disconnect == 0) { if (globalreg->timestamp.tv_sec - last_frame > 20) { if (tcpcli->Valid() == 0) { _MSG("Unable to establish connection to Kismet drone server at " + string(cli_host) + ":" + IntToString(cli_port) + " in 20 seconds, " "attempting to reconnect", MSGFLAG_ERROR); last_disconnect = 0; last_frame = globalreg->timestamp.tv_sec; } else { _MSG("No frames from Kismet drone server at " + string(cli_host) + ":" + IntToString(cli_port) + " in 20 seconds, reconnecting", MSGFLAG_ERROR); last_disconnect = last_frame = globalreg->timestamp.tv_sec; } Reconnect(); } } return 1; } void DroneClientFrame::SourceActionHandler(pst_packetsource *src, int action, int flags) { unsigned int cmd = DRONE_CHS_CMD_NONE; if (action == SOURCEACT_HOPENABLE || action == SOURCEACT_HOPDISABLE) { cmd = DRONE_CHS_CMD_SETHOP; } else if (action == SOURCEACT_CHVECTOR) { cmd = DRONE_CHS_CMD_SETVEC; } else if (action == SOURCEACT_CHHOPDWELL) { cmd = DRONE_CHS_CMD_SETHOPDWELL; } } int DroneClientFrame::Reconnect() { ostringstream osstr; if (tcpcli == NULL) return 0; tcpcli->KillConnection(); if (cli_type == 0) { netclient->Connect(cli_host, cli_port, dcf_connect_hook, this); return 1; } return 0; } int DroneClientFrame::KillConnection() { ClientFramework::KillConnection(); // last_disconnect = globalreg->timestamp.tv_sec; // Kill all our faked packet sources for (map<uuid, int>::iterator i = virtual_src_map.begin(); i != virtual_src_map.end(); ++i) { pst_packetsource *psrc = globalreg->sourcetracker->FindLivePacketSourceUUID(i->first); KisPacketSource *src = psrc->strong_source; if (src != NULL) { globalreg->sourcetracker->RemoveLivePacketSource(src); delete src; } } virtual_src_map.erase(virtual_src_map.begin(), virtual_src_map.end()); return 1; } int DroneClientFrame::Shutdown() { if (tcpcli != NULL) { tcpcli->FlushRings(); tcpcli->KillConnection(); } return 1; } int DroneClientFrame::Poll(fd_set &in_rset, fd_set& in_wset) { if (netclient == NULL) return 0; int ret = netclient->Poll(in_rset, in_wset); if (ret < 0) { KillConnection(); last_disconnect = globalreg->timestamp.tv_sec; } return ret; } int DroneClientFrame::ParseData() { int len, rlen; uint8_t *buf; ostringstream osstr; unsigned int pos = 0; if (netclient == NULL) return 0; if (netclient->Valid() == 0) return 0; // Allocate a buffer len = netclient->FetchReadLen(); buf = new uint8_t[len + 1]; // Fetch all the data we have queued if (netclient->ReadData(buf, len, &rlen) < 0) { if (reconnect) { _MSG("Kismet drone client failed to read data from the " "TCP connection. Will attempt to reconnect in 5 seconds", MSGFLAG_ERROR); KillConnection(); last_disconnect = globalreg->timestamp.tv_sec; delete[] buf; return 0; } else { delete[] buf; _MSG("Kismet drone client failed to read data from the " "TCP connection and reconnecting not enabled.", MSGFLAG_ERROR); return -1; } } // Bail if we're too small to hold even a packet header if ((unsigned int) rlen < sizeof(drone_packet)) { delete[] buf; return 0; } // Loop through while (rlen > (int) pos && (rlen - pos) >= (int) sizeof(drone_packet)) { drone_packet *dpkt = (drone_packet *) &(buf[pos]); if (kis_ntoh32(dpkt->sentinel) != DroneSentinel) { /* fprintf(stderr, "debug - pkt sentinel mismatch pos %u rlen %u\n", pos, rlen); for (unsigned int z = pos; z < rlen; z++) fprintf(stderr, "%02x ", buf[z]); fprintf(stderr, "\n"); */ if (reconnect) { _MSG("Kismet drone client failed to find the sentinel " "value in a packet header, dropping connection. Will " "attempt to reconnect in 5 seconds", MSGFLAG_ERROR); KillConnection(); last_disconnect = globalreg->timestamp.tv_sec; delete[] buf; return 0; } else { delete[] buf; _MSG("Kismet drone client failed to find the sentinel " "value in a packet header. This error is fatal because " "drone reconnecting is not enabled", MSGFLAG_ERROR); return -1; } } unsigned int dplen = kis_ntoh32(dpkt->data_len); // fprintf(stderr, "debug - dplen %u\n", dplen); // Check for incomplete packets if (rlen - (int) pos < (int) (dplen + sizeof(drone_packet))) { break; } netclient->MarkRead(dplen + sizeof(drone_packet)); pos += dplen + sizeof(drone_packet); unsigned int dcid = kis_ntoh32(dpkt->drone_cmdnum); // Handle the packet types if (dcid == DRONE_CMDNUM_NULL) { // Nothing special to do here, treat it as an update packet } else if (dcid == DRONE_CMDNUM_HELO) { drone_helo_packet *hpkt = (drone_helo_packet *) dpkt->data; char rname[33]; sscanf((char *) hpkt->host_name, "%32s", rname); remote_name = string(rname); if (kis_ntoh32(hpkt->drone_version) != KIS_DRONE_VERSION) { osstr << "Kismet drone client got remote protocol " "version " << kis_ntoh32(hpkt->drone_version) << " but uses " "version " << KIS_DRONE_VERSION << ". All features or " "components may not be available"; _MSG(osstr.str(), MSGFLAG_INFO); } else { osstr << "Kismet drone client connected to remote server " "\"" + remote_name + "\" using protocol version " << kis_ntoh32(hpkt->drone_version); _MSG(osstr.str(), MSGFLAG_INFO); } } else if (dcid == DRONE_CMDNUM_STRING) { drone_string_packet *spkt = (drone_string_packet *) dpkt->data; string msg = string("DRONE(" + remote_name + ") - "); uint32_t len = kis_ntoh32(spkt->msg_len); // Don't trust us to have a final terminator, copy manually for (unsigned int x = 0; x < len; x++) { msg += spkt->msg[x]; } // Inject it into the messagebus w/ the normal _MSG(msg, kis_ntoh32(spkt->msg_flags)); } else if (dcid == DRONE_CMDNUM_SOURCE) { drone_source_packet *spkt = (drone_source_packet *) dpkt->data; uint32_t sbm = kis_ntoh32(spkt->source_content_bitmap); uint16_t sourcelen = kis_ntoh16(spkt->source_hdr_len); uint16_t rofft = 0; // New source data we're making uuid new_uuid; string namestr, interfacestr, typestr; char strbuffer[17]; int src_invalidated = 0; int channel_hop = -1, channel_dwell = -1, channel_rate = -1; // Ghetto method of tracking how many components we've filled in. // We should get a 8 to make a source. int comp_counter = 0; if ((sbm & DRONEBIT(DRONE_SRC_UUID)) && (rofft + sizeof(drone_trans_uuid) <= sourcelen)) { UUID_CONV_DRONE(&(spkt->uuid), new_uuid); comp_counter++; rofft += sizeof(drone_trans_uuid); } if ((sbm & DRONEBIT(DRONE_SRC_INVALID)) && (rofft + 2 <= sourcelen)) { src_invalidated = kis_ntoh16(spkt->invalidate); comp_counter++; rofft += 2; } if ((sbm & DRONEBIT(DRONE_SRC_NAMESTR)) && (rofft + 16 <= sourcelen)) { sscanf((const char *) spkt->name_str, "%16s", strbuffer); namestr = string(strbuffer); comp_counter++; rofft += 16; } if ((sbm & DRONEBIT(DRONE_SRC_INTSTR)) && (rofft + 16 <= sourcelen)) { sscanf((const char *) spkt->interface_str, "%16s", strbuffer); interfacestr = string(strbuffer); comp_counter++; rofft += 16; } if ((sbm & DRONEBIT(DRONE_SRC_TYPESTR)) && (rofft + 16 <= sourcelen)) { sscanf((const char *) spkt->type_str, "%16s", strbuffer); typestr = string(strbuffer); comp_counter++; rofft += 16; } if ((sbm & DRONEBIT(DRONE_SRC_CHANHOP)) && (rofft + 1 <= sourcelen)) { channel_hop = spkt->channel_hop; comp_counter++; rofft += 1; } if ((sbm & DRONEBIT(DRONE_SRC_CHANNELDWELL)) && (rofft + 2 <= sourcelen)) { channel_dwell = kis_ntoh16(spkt->channel_dwell); comp_counter++; rofft += 2; } if ((sbm & DRONEBIT(DRONE_SRC_CHANNELRATE)) && (rofft + 2 <= sourcelen)) { channel_rate = kis_ntoh16(spkt->channel_rate); comp_counter++; rofft += 2; } if (comp_counter >= 8 && src_invalidated == 0 && new_uuid.error == 0) { _MSG("Live-adding pseudo capsources from drones temporarily disabled until " "rewrite.", MSGFLAG_INFO); #if 0 // Make sure the source doesn't exist in the real tracker pst_packetsource *rsrc = globalreg->sourcetracker->FindLivePacketSourceUUID(new_uuid); if (rsrc == NULL) { ostringstream osstr; osstr << interfacestr << ":uuid=" << new_uuid.UUID2String(); if (namestr != "") osstr << ",name=" << namestr; osstr << ",channellist=n/a"; // Derive the rest of the source options if (channel_hop == 0) osstr << ",hop=false"; if (channel_dwell > 0) { osstr << ",dwell=" << channel_dwell; } else if (channel_rate > 0) { osstr << ",velocity=" << channel_rate; } // Make the strong source with no options, we'll push them // via the sourcetracker registration PacketSource_DroneRemote *rem = new PacketSource_DroneRemote(globalreg, interfacestr, NULL); rem->SetDroneFrame(this); if (globalreg->sourcetracker->AddLivePacketSource( osstr.str(), rem) < 0) { _MSG("Failed to add drone virtual source for remote " "source " + interfacestr + " something went wrong.", MSGFLAG_ERROR); delete rem; break; } rem->SetPST( globalreg->sourcetracker->FindLivePacketSourceUUID(new_uuid)); virtual_src_map[new_uuid] = 1; } } else if (src_invalidated == 1 && new_uuid.error == 0) { pst_packetsource *rsrc = globalreg->sourcetracker->FindLivePacketSourceUUID(new_uuid); // Make sure the source really exists, and make sure its one of our // virtual sources, because we don't let a drone try to cancel a // local real source if (rsrc != NULL && virtual_src_map.find(new_uuid) != virtual_src_map.end()) { // We don't have to close anything since the virtual interfaces // are just nonsense _MSG("Removing capture source " + rsrc->strong_source->FetchName() + ", UUID " + new_uuid.UUID2String() + " from remote drone", MSGFLAG_INFO); globalreg->sourcetracker->RemovePacketSource(rsrc); virtual_src_map.erase(new_uuid); } #endif } } else if (dcid == DRONE_CMDNUM_CAPPACKET) { drone_capture_packet *dcpkt = (drone_capture_packet *) dpkt->data; uint32_t poffst = 0; kis_packet *newpack = globalreg->packetchain->GeneratePacket(); uint32_t cbm = kis_ntoh32(dcpkt->cap_content_bitmap); if ((cbm & DRONEBIT(DRONE_CONTENT_RADIO))) { drone_capture_sub_radio *dsr = (drone_capture_sub_radio *) &(dcpkt->content[poffst]); uint16_t sublen = kis_ntoh16(dsr->radio_hdr_len); // Make sure our subframe is contained within the larger frame if (poffst + sublen > dplen) { _MSG("Kismet drone client got a subframe with a length " "greater than the total packet length. This " "corruption may be accidental or malicious.", MSGFLAG_ERROR); globalreg->packetchain->DestroyPacket(newpack); delete[] buf; return 0; } kis_layer1_packinfo *radio = new kis_layer1_packinfo; uint16_t rofft = 0; // Extract the components as long as theres space... in theory it // should be an error condition if it's not filled in, but // if we just handle it properly... uint32_t rcbm = kis_ntoh32(dsr->radio_content_bitmap); if ((rcbm & DRONEBIT(DRONE_RADIO_ACCURACY)) && (rofft + 2 <= sublen)) { radio->accuracy = kis_ntoh16(dsr->radio_accuracy); rofft += 2; } if ((rcbm & DRONEBIT(DRONE_RADIO_FREQ_MHZ)) && (rofft + 2 <= sublen)) { radio->freq_mhz = kis_ntoh16(dsr->radio_freq_mhz); rofft += 2; } if ((rcbm & DRONEBIT(DRONE_RADIO_SIGNAL_DBM)) && (rofft + 2 <= sublen)) { radio->signal_dbm = (int16_t) kis_ntoh16(dsr->radio_signal_dbm); rofft += 2; } if ((rcbm & DRONEBIT(DRONE_RADIO_NOISE_DBM)) && (rofft + 2 <= sublen)) { radio->noise_dbm = (int16_t) kis_ntoh16(dsr->radio_noise_dbm); rofft += 2; } if ((rcbm & DRONEBIT(DRONE_RADIO_CARRIER)) && (rofft + 4 <= sublen)) { radio->carrier = (phy_carrier_type) kis_ntoh32(dsr->radio_carrier); rofft += 4; } if ((rcbm & DRONEBIT(DRONE_RADIO_ENCODING)) && (rofft + 4 <= sublen)) { radio->encoding = (phy_encoding_type) kis_ntoh32(dsr->radio_encoding); rofft += 4; } if ((rcbm & DRONEBIT(DRONE_RADIO_DATARATE)) && (rofft + 4 <= sublen)) { radio->datarate = kis_ntoh32(dsr->radio_datarate); rofft += 4; } if ((rcbm & DRONEBIT(DRONE_RADIO_SIGNAL_RSSI)) && (rofft + 2 <= sublen)) { radio->signal_rssi = (int16_t) kis_ntoh16(dsr->radio_signal_rssi); rofft += 2; } if ((rcbm & DRONEBIT(DRONE_RADIO_NOISE_RSSI)) && (rofft + 2 <= sublen)) { radio->noise_rssi = (int16_t) kis_ntoh16(dsr->radio_noise_rssi); rofft += 2; } newpack->insert(_PCM(PACK_COMP_RADIODATA), radio); // Jump to the end of this packet poffst += sublen; } if ((cbm & DRONEBIT(DRONE_CONTENT_GPS))) { drone_capture_sub_gps *dsg = (drone_capture_sub_gps *) &(dcpkt->content[poffst]); uint16_t sublen = kis_ntoh16(dsg->gps_hdr_len); // Make sure our subframe is contained within the larger frame if (poffst + sublen > dplen) { _MSG("Kismet drone client got a subframe with a length " "greater than the total packet length. This " "corruption may be accidental or malicious.", MSGFLAG_ERROR); delete[] buf; globalreg->packetchain->DestroyPacket(newpack); return 0; } kis_gps_packinfo *gpsinfo = new kis_gps_packinfo; uint16_t rofft = 0; uint32_t gcbm = kis_ntoh32(dsg->gps_content_bitmap); if ((gcbm & DRONEBIT(DRONE_GPS_FIX)) && (rofft + 2 <= sublen)) { gpsinfo->gps_fix = kis_ntoh16(dsg->gps_fix); rofft += 2; } if ((gcbm & DRONEBIT(DRONE_GPS_LAT)) && (rofft + sizeof(drone_trans_double) <= sublen)) { DOUBLE_CONV_DRONE(gpsinfo->lat, &(dsg->gps_lat)); rofft += sizeof(drone_trans_double); } if ((gcbm & DRONEBIT(DRONE_GPS_LON)) && (rofft + sizeof(drone_trans_double) <= sublen)) { DOUBLE_CONV_DRONE(gpsinfo->lon, &(dsg->gps_lon)); rofft += sizeof(drone_trans_double); } if ((gcbm & DRONEBIT(DRONE_GPS_ALT)) && (rofft + sizeof(drone_trans_double) <= sublen)) { DOUBLE_CONV_DRONE(gpsinfo->alt, &(dsg->gps_alt)); rofft += sizeof(drone_trans_double); } if ((gcbm & DRONEBIT(DRONE_GPS_SPD)) && (rofft + sizeof(drone_trans_double) <= sublen)) { DOUBLE_CONV_DRONE(gpsinfo->spd, &(dsg->gps_spd)); rofft += sizeof(drone_trans_double); } if ((gcbm & DRONEBIT(DRONE_GPS_HEADING)) && (rofft + sizeof(drone_trans_double) <= sublen)) { DOUBLE_CONV_DRONE(gpsinfo->heading, &(dsg->gps_heading)); rofft += sizeof(drone_trans_double); } newpack->insert(_PCM(PACK_COMP_GPS), gpsinfo); // Jump to the end of this packet poffst += sublen; } if ((cbm & DRONEBIT(DRONE_CONTENT_FCS))) { kis_fcs_bytes *fcschunk = new kis_fcs_bytes; memcpy(fcschunk->fcs, &(dcpkt->content[poffst]), 4); fcschunk->fcsvalid = 1; newpack->insert(_PCM(PACK_COMP_FCSBYTES), fcschunk); // Jump to the end of this packet poffst += 4; } if ((cbm & DRONEBIT(DRONE_CONTENT_IEEEPACKET))) { // Jump to thend of the capframe poffst = kis_ntoh32(dcpkt->cap_packet_offset); drone_capture_sub_data *ds11 = (drone_capture_sub_data *) &(dcpkt->content[poffst]); uint16_t sublen = kis_ntoh16(ds11->data_hdr_len); // Make sure our subframe is contained within the larger frame if (poffst + sublen > dplen) { _MSG("Kismet drone client got a subframe with a length " "greater than the total packet length. This " "corruption may be accidental or malicious.", MSGFLAG_ERROR); delete[] buf; globalreg->packetchain->DestroyPacket(newpack); return 0; } // Make a data chunk, assuming 802.11 if we don't have // a DLT, otherwise with the remote DLT kis_datachunk *chunk = new kis_datachunk; uuid new_uuid; uint16_t rofft = 0; uint32_t ecbm = kis_ntoh32(ds11->data_content_bitmap); if ((ecbm & DRONEBIT(DRONE_DATA_UUID)) && (rofft + sizeof(drone_trans_uuid) <= sublen)) { UUID_CONV_DRONE(&(ds11->uuid), new_uuid); rofft += sizeof(drone_trans_uuid); } if ((ecbm & DRONEBIT(DRONE_DATA_PACKLEN)) && (rofft + 2 <= sublen)) { chunk->length = kismin(kis_ntoh16(ds11->packet_len), (uint32_t) MAX_PACKET_LEN); rofft += 2; } if ((ecbm & DRONEBIT(DRONE_DATA_TVSEC)) && (rofft + 8 <= sublen)) { newpack->ts.tv_sec = kis_ntoh64(ds11->tv_sec); rofft += 8; } if ((ecbm & DRONEBIT(DRONE_DATA_TVUSEC)) && (rofft + 8 <= sublen)) { newpack->ts.tv_usec = kis_ntoh64(ds11->tv_usec); rofft += 8; } if ((ecbm & DRONEBIT(DRONE_DATA_DLT)) && (rofft + 4 <= sublen)) { chunk->dlt = kis_ntoh32(ds11->dlt); rofft += 4; } // Fill in the rest of the chunk if it makes sense to if (chunk->length == 0) { delete chunk; } else { if (poffst + sublen + chunk->length > dplen) { _MSG("Kismet drone client got a 80211 frame with a length " "greater than the total packet length. This " "corruption may be accidental or malicious.", MSGFLAG_ERROR); delete[] buf; delete chunk; globalreg->packetchain->DestroyPacket(newpack); return 0; } chunk->data = new uint8_t[chunk->length]; uint8_t *rawdat = (uint8_t *) ds11; memcpy(chunk->data, &(rawdat[sublen]), chunk->length); newpack->insert(_PCM(PACK_COMP_LINKFRAME), chunk); } // Fill in the capture source if we can find it locally, and only // accept from sources we understand, otherwise it shows up as // from the drone itself, as long as we have a local source if (new_uuid.error == 0 && virtual_src_map.find(new_uuid) != virtual_src_map.end()) { PacketSource_DroneRemote *rsrc = NULL; pst_packetsource *psrc = globalreg->sourcetracker->FindLivePacketSourceUUID(new_uuid); if (psrc != NULL && psrc->strong_source != NULL) { rsrc = (PacketSource_DroneRemote *) psrc->strong_source; // Safe because we only do it on our own virtuals rsrc->IncrementNumPackets(); kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = rsrc; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); } } else if (packetsource != NULL) { kis_ref_capsource *csrc_ref = new kis_ref_capsource; csrc_ref->ref_source = (KisPacketSource *) packetsource; newpack->insert(_PCM(PACK_COMP_KISCAPSRC), csrc_ref); } } last_frame = time(0); globalreg->packetchain->ProcessPacket(newpack); } } delete[] buf; return 1; } int DroneClientFrame::SendPacket(drone_packet *in_pack) { if (netclient->Valid() == 0 && last_disconnect != 0) { if (Reconnect() <= 0) return 0; } int nlen = kis_ntoh32(in_pack->data_len) + sizeof(drone_packet); if (netclient->WriteData((void *) in_pack, nlen) < 0 || globalreg->fatal_condition) { last_disconnect = time(0); return -1; } return 1; } int DroneClientFrame::SendChannelData(pst_packetsource *in_src, unsigned int in_cmd) { drone_packet *dpkt = (drone_packet *) malloc(sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_channelset_packet))); memset(dpkt, 0, sizeof(uint8_t) * (sizeof(drone_packet) + sizeof(drone_channelset_packet))); dpkt->sentinel = kis_hton32(DroneSentinel); dpkt->drone_cmdnum = kis_hton32(DRONE_CMDNUM_CHANNELSET); dpkt->data_len = kis_hton32(sizeof(drone_channelset_packet)); drone_channelset_packet *cpkt = (drone_channelset_packet *) dpkt->data; cpkt->channelset_hdr_len = kis_hton16(sizeof(drone_channelset_packet)); cpkt->channelset_content_bitmap = kis_hton32(DRONEBIT(DRONE_CHANNELSET_UUID) | DRONEBIT(DRONE_CHANNELSET_CMD) | DRONEBIT(DRONE_CHANNELSET_CURCH) | DRONEBIT(DRONE_CHANNELSET_HOP) | DRONEBIT(DRONE_CHANNELSET_NUMCH) | DRONEBIT(DRONE_CHANNELSET_CHANNELS) | DRONEBIT(DRONE_CHANNELSET_CHANNELSDWELL) | DRONEBIT(DRONE_CHANNELSET_HOPRATE) | DRONEBIT(DRONE_CHANNELSET_HOPDWELL)); DRONE_CONV_UUID(in_src->strong_source->FetchUUID(), &(cpkt->uuid)); cpkt->command = kis_ntoh16(in_cmd); if (in_cmd == DRONE_CHS_CMD_SETHOP) { cpkt->cur_channel = kis_hton16(in_src->channel); cpkt->channel_hop = kis_hton16(in_src->channel_hop); } else if (in_cmd == DRONE_CHS_CMD_SETVEC) { pst_channellist *chl = globalreg->sourcetracker->FetchSourceChannelList(in_src); if (chl == NULL) { cpkt->num_channels = 0; } else { cpkt->num_channels = kis_hton16(chl->channel_vec.size()); for (unsigned int c = 0; c < kismin(chl->channel_vec.size(), IPC_SOURCE_MAX_CHANS); c++) { if (chl->channel_vec[c].range == 0) { cpkt->chandata[c].u.chan_t.channel = kis_hton16(chl->channel_vec[c].u.chan_t.channel); cpkt->chandata[c].u.chan_t.dwell = kis_hton16(chl->channel_vec[c].u.chan_t.channel); } else { cpkt->chandata[c].u.range_t.start = kis_hton16(chl->channel_vec[c].u.range_t.start | (1 << 15)); cpkt->chandata[c].u.range_t.end = kis_hton16(chl->channel_vec[c].u.range_t.end); cpkt->chandata[c].u.range_t.width = kis_hton16(chl->channel_vec[c].u.range_t.width); cpkt->chandata[c].u.range_t.iter = kis_hton16(chl->channel_vec[c].u.range_t.iter); } /* cpkt->channels[c] = kis_hton16(chl->channel_vec[c].channel); cpkt->channels_dwell[c] = kis_hton16(chl->channel_vec[c].dwell); */ } } } else if (in_cmd == DRONE_CHS_CMD_SETHOPDWELL) { cpkt->channel_rate = kis_hton16(in_src->channel_rate); cpkt->channel_dwell = kis_hton16(in_src->channel_dwell); } int ret = 0; ret = SendPacket(dpkt); free(dpkt); return ret; } PacketSource_Drone::PacketSource_Drone(GlobalRegistry *in_globalreg, string in_interface, vector<opt_pair> *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { droneframe = NULL; reconnect = 1; // The master source isn't channel capable channel_capable = 0; // Automatically reconnect reconnect = 1; // Look for the host and port if (FetchOpt("host", in_opts) == "" || FetchOpt("port", in_opts) == "") { _MSG("Drone source missing 'host' or 'port' option. Kismet now uses the " "'host' and 'port' source options to configure remote Drones (for example " "ncsource=drone:host=127.0.0.1,port=2502,reconnect=true)", MSGFLAG_ERROR); error = 1; return; } connecturl = "tcp://" + FetchOpt("host", in_opts) + ":" + FetchOpt("port", in_opts); // Look for the reconnect parm // if (FetchOpt("reconnect", in_opts) != "" && // StrLower(FetchOpt("reconnect", in_opts)) != "true") { if (FetchOptBoolean("reconnect", in_opts, 1)) { reconnect = 0; _MSG("Disabling reconnection on drone source '" + name + "' '" + interface + "'. If the connection fails this source will remain " "inactive.", MSGFLAG_INFO); } } int PacketSource_Drone::RegisterSources(Packetsourcetracker *tracker) { // Register the pcapfile source based off ourselves, nonroot, nonchildcontrol tracker->RegisterPacketProto("drone", this, "n/a", 0); return 1; } PacketSource_Drone::~PacketSource_Drone() { if (droneframe != NULL) { droneframe->Shutdown(); delete droneframe; } } int PacketSource_Drone::OpenSource() { if (error) { _MSG("packetsource drone (" + name + ") failed to initialize " "drone framework and open connection, check previous errors " "for why.", MSGFLAG_PRINTERROR); return -1; } if (droneframe == NULL) droneframe = new DroneClientFrame(globalreg); droneframe->SetPacketsource((void *) this); if (droneframe->OpenConnection(connecturl, reconnect) < 0 || globalreg->fatal_condition) { _MSG("Packetsource drone (" + name + ") failed to create drone " "framework and open connection", MSGFLAG_PRINTERROR); error = 1; return -1; } return 1; } int PacketSource_Drone::CloseSource() { if (droneframe == NULL) return 0; droneframe->Shutdown(); delete droneframe; droneframe = NULL; return 1; } void PacketSource_Drone::FetchRadioData(kis_packet *in_packet) { // Nothing to do here return; } int PacketSource_Drone::FetchDescriptor() { // Nothing to do here, the pollable droneclientframe handles it return -1; } int PacketSource_Drone::Poll() { // Nothing to do here, we should never even be called. Pollable // droneclientframe handles it return 0; } PacketSource_DroneRemote::~PacketSource_DroneRemote() { // nothing right now } int PacketSource_DroneRemote::RegisterSources(Packetsourcetracker *tracker) { // Nothing to do here, since we don't have any types per se that belong // to us return 1; } int PacketSource_DroneRemote::SetChannel(unsigned int in_ch) { if (droneframe == NULL) return 0; if (droneframe->Valid() == 0) return 0; // Toss the error, we always "succeed" droneframe->SendChannelData(pstsource, DRONE_CHS_CMD_SETCUR); return 1; } int PacketSource_DroneRemote::FetchChannel() { return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/dumpfile_nettxt.cc���������������������������������������������������������������0000664�0001750�0001750�00000055453�12124602454�017211� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <errno.h> #include "globalregistry.h" #include "alertracker.h" #include "dumpfile_nettxt.h" #include "packetsource.h" #include "packetsourcetracker.h" #include "netracker.h" Dumpfile_Nettxt::Dumpfile_Nettxt() { fprintf(stderr, "FATAL OOPS: Dumpfile_Nettxt called with no globalreg\n"); exit(1); } Dumpfile_Nettxt::Dumpfile_Nettxt(GlobalRegistry *in_globalreg) : Dumpfile(in_globalreg) { globalreg = in_globalreg; txtfile = NULL; type = "nettxt"; if (globalreg->netracker == NULL) { fprintf(stderr, "FATAL OOPS: Netracker missing before Dumpfile_Nettxt\n"); exit(1); } if (globalreg->kismet_config == NULL) { fprintf(stderr, "FATAL OOPS: Config file missing before Dumpfile_Nettxt\n"); exit(1); } if (globalreg->alertracker == NULL) { fprintf(stderr, "FATAL OOPS: Alertacker missing before dumpfile_nettxt\n"); exit(1); } // Find the file name if ((fname = ProcessConfigOpt("nettxt")) == "" || globalreg->fatal_condition) { return; } if ((txtfile = fopen(fname.c_str(), "w")) == NULL) { _MSG("Failed to open nettxt log file '" + fname + "': " + strerror(errno), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return; } globalreg->RegisterDumpFile(this); _MSG("Opened nettxt log file '" + fname + "'", MSGFLAG_INFO); } Dumpfile_Nettxt::~Dumpfile_Nettxt() { // Close files if (txtfile != NULL) { Flush(); } txtfile = NULL; if (export_filter != NULL) delete export_filter; } int Dumpfile_Nettxt::Flush() { if (txtfile != NULL) fclose(txtfile); string tempname = fname + ".temp"; if ((txtfile = fopen(tempname.c_str(), "w")) == NULL) { _MSG("Failed to open temporary nettxt file for writing: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } fprintf(txtfile, "Kismet (http://www.kismetwireless.net)\n" "%.24s - Kismet %s.%s.%s\n" "-----------------\n\n", ctime(&(globalreg->start_time)), globalreg->version_major.c_str(), globalreg->version_minor.c_str(), globalreg->version_tiny.c_str()); // Get the tracked network and client->ap maps const map<mac_addr, Netracker::tracked_network *> tracknet = globalreg->netracker->FetchTrackedNets(); // Get the alerts const vector<kis_alert_info *> *alerts = globalreg->alertracker->FetchBacklog(); map<mac_addr, Netracker::tracked_network *>::const_iterator x; map<mac_addr, Netracker::tracked_client *>::const_iterator y; int netnum = 0; // Dump all the networks for (x = tracknet.begin(); x != tracknet.end(); ++x) { netnum++; if (export_filter->RunFilter(x->second->bssid, mac_addr(0), mac_addr(0))) continue; Netracker::tracked_network *net = x->second; if (net->type == network_remove) continue; string ntype; switch (net->type) { case network_ap: ntype = "infrastructure"; break; case network_adhoc: ntype = "ad-hoc"; break; case network_probe: ntype = "probe"; break; case network_data: ntype = "data"; break; case network_turbocell: ntype = "turbocell"; break; default: ntype = "unknown"; break; } fprintf(txtfile, "Network %d: BSSID %s\n", netnum, net->bssid.Mac2String().c_str()); fprintf(txtfile, " Manuf : %s\n", net->manuf.c_str()); fprintf(txtfile, " First : %.24s\n", ctime(&(net->first_time))); fprintf(txtfile, " Last : %.24s\n", ctime(&(net->last_time))); fprintf(txtfile, " Type : %s\n", ntype.c_str()); fprintf(txtfile, " BSSID : %s\n", net->bssid.Mac2String().c_str()); int ssidnum = 1; for (map<uint32_t, Netracker::adv_ssid_data *>::iterator m = net->ssid_map.begin(); m != net->ssid_map.end(); ++m) { string typestr; if (m->second->type == ssid_beacon) typestr = "Beacon"; else if (m->second->type == ssid_proberesp) typestr = "Probe Response"; else if (m->second->type == ssid_probereq) typestr = "Probe Request"; else if (m->second->type == ssid_file) typestr = "Cached SSID"; fprintf(txtfile, " SSID %d\n", ssidnum); fprintf(txtfile, " Type : %s\n", typestr.c_str()); fprintf(txtfile, " SSID : \"%s\" %s\n", m->second->ssid.c_str(), m->second->ssid_cloaked ? "(Cloaked)" : ""); if (m->second->beacon_info.length() > 0) fprintf(txtfile, " Info : %s\n", m->second->beacon_info.c_str()); fprintf(txtfile, " First : %.24s\n", ctime(&(m->second->first_time))); fprintf(txtfile, " Last : %.24s\n", ctime(&(m->second->last_time))); fprintf(txtfile, " Max Rate : %2.1f\n", m->second->maxrate); if (m->second->beaconrate != 0) fprintf(txtfile, " Beacon : %d\n", m->second->beaconrate); fprintf(txtfile, " Packets : %d\n", m->second->packets); if (m->second->dot11d_vec.size() > 0) { fprintf(txtfile, " Country : %s\n", m->second->dot11d_country.c_str()); for (unsigned int z = 0; z < m->second->dot11d_vec.size(); z++) { fprintf(txtfile, " Chan Range: %u-%u %u dBm\n", m->second->dot11d_vec[z].startchan, m->second->dot11d_vec[z].startchan + m->second->dot11d_vec[z].numchan - 1, m->second->dot11d_vec[z].txpower); } } if (m->second->cryptset == 0) fprintf(txtfile, " Encryption : None\n"); if (m->second->cryptset == crypt_wep) fprintf(txtfile, " Encryption : WEP\n"); if (m->second->cryptset & crypt_layer3) fprintf(txtfile, " Encryption : Layer3\n"); if (m->second->cryptset & crypt_wpa_migmode) fprintf(txtfile, " Encryption : WPA Migration Mode\n"); if (m->second->cryptset & crypt_wep40) fprintf(txtfile, " Encryption : WEP40\n"); if (m->second->cryptset & crypt_wep104) fprintf(txtfile, " Encryption : WEP104\n"); /* if (m->second->cryptset & crypt_wpa) fprintf(txtfile, " Encryption : WPA\n"); */ if (m->second->cryptset & crypt_psk) fprintf(txtfile, " Encryption : WPA+PSK\n"); if (m->second->cryptset & crypt_tkip) fprintf(txtfile, " Encryption : WPA+TKIP\n"); if (m->second->cryptset & crypt_aes_ocb) fprintf(txtfile, " Encryption : WPA+AES-OCB\n"); if (m->second->cryptset & crypt_aes_ccm) fprintf(txtfile, " Encryption : WPA+AES-CCM\n"); if (m->second->cryptset & crypt_leap) fprintf(txtfile, " Encryption : WPA+LEAP\n"); if (m->second->cryptset & crypt_ttls) fprintf(txtfile, " Encryption : WPA+TTLS\n"); if (m->second->cryptset & crypt_tls) fprintf(txtfile, " Encryption : WPA+TLS\n"); if (m->second->cryptset & crypt_peap) fprintf(txtfile, " Encryption : WPA+PEAP\n"); if (m->second->cryptset & crypt_isakmp) fprintf(txtfile, " Encryption : ISAKMP\n"); if (m->second->cryptset & crypt_pptp) fprintf(txtfile, " Encryption : PPTP\n"); if (m->second->cryptset & crypt_fortress) fprintf(txtfile, " Encryption : Fortress\n"); if (m->second->cryptset & crypt_keyguard) fprintf(txtfile, " Encryption : Keyguard\n"); ssidnum++; } fprintf(txtfile, " Channel : %d\n", net->channel); for (map<unsigned int, unsigned int>::const_iterator fmi = net->freq_mhz_map.begin(); fmi != net->freq_mhz_map.end(); ++fmi) { float perc = ((float) fmi->second / (float) (net->llc_packets + net->data_packets)) * 100; fprintf(txtfile, " Frequency : %d - %d packets, %.02f%%\n", fmi->first, fmi->second, perc); } fprintf(txtfile, " Max Seen : %d\n", net->snrdata.maxseenrate * 100); if (net->snrdata.carrierset & (1 << (int) carrier_80211b)) fprintf(txtfile, " Carrier : IEEE 802.11b\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211bplus)) fprintf(txtfile, " Carrier : IEEE 802.11b+\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211a)) fprintf(txtfile, " Carrier : IEEE 802.11a\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211g)) fprintf(txtfile, " Carrier : IEEE 802.11g\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211fhss)) fprintf(txtfile, " Carrier : IEEE 802.11 FHSS\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211dsss)) fprintf(txtfile, " Carrier : IEEE 802.11 DSSS\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211n20)) fprintf(txtfile, " Carrier : IEEE 802.11n 20MHz\n"); if (net->snrdata.carrierset & (1 << (int) carrier_80211n40)) fprintf(txtfile, " Carrier : IEEE 802.11n 40MHz\n"); if (net->snrdata.encodingset & (1 << (int) encoding_cck)) fprintf(txtfile, " Encoding : CCK\n"); if (net->snrdata.encodingset & (1 << (int) encoding_pbcc)) fprintf(txtfile, " Encoding : PBCC\n"); if (net->snrdata.encodingset & (1 << (int) encoding_ofdm)) fprintf(txtfile, " Encoding : OFDM\n"); if (net->snrdata.encodingset & (1 << (int) encoding_dynamiccck)) fprintf(txtfile, " Encoding : Dynamic CCK-OFDM\n"); if (net->snrdata.encodingset & (1 << (int) encoding_gfsk)) fprintf(txtfile, " Encoding : GFSK\n"); fprintf(txtfile, " LLC : %d\n", net->llc_packets); fprintf(txtfile, " Data : %d\n", net->data_packets); fprintf(txtfile, " Crypt : %d\n", net->crypt_packets); fprintf(txtfile, " Fragments : %d\n", net->fragments); fprintf(txtfile, " Retries : %d\n", net->retries); fprintf(txtfile, " Total : %d\n", net->llc_packets + net->data_packets); fprintf(txtfile, " Datasize : %llu\n", (long long unsigned int) net->datasize); if (net->gpsdata.gps_valid) { fprintf(txtfile, " Min Pos : Lat %f Lon %f Alt %f Spd %f\n", net->gpsdata.min_lat, net->gpsdata.min_lon, net->gpsdata.min_alt, net->gpsdata.min_spd); fprintf(txtfile, " Max Pos : Lat %f Lon %f Alt %f Spd %f\n", net->gpsdata.max_lat, net->gpsdata.max_lon, net->gpsdata.max_alt, net->gpsdata.max_spd); fprintf(txtfile, " Peak Pos : Lat %f Lon %f Alt %f\n", net->snrdata.peak_lat, net->snrdata.peak_lon, net->snrdata.peak_alt); fprintf(txtfile, " Avg Pos : AvgLat %f AvgLon %f AvgAlt %f\n", net->gpsdata.aggregate_lat, net->gpsdata.aggregate_lon, net->gpsdata.aggregate_alt); } if (net->guess_ipdata.ip_type > ipdata_factoryguess && net->guess_ipdata.ip_type < ipdata_group) { string iptype; switch (net->guess_ipdata.ip_type) { case ipdata_udptcp: iptype = "UDP/TCP"; break; case ipdata_arp: iptype = "ARP"; break; case ipdata_dhcp: iptype = "DHCP"; break; default: iptype = "Unknown"; break; } fprintf(txtfile, " IP Type : %s\n", iptype.c_str()); fprintf(txtfile, " IP Block : %s\n", inet_ntoa(net->guess_ipdata.ip_addr_block)); fprintf(txtfile, " IP Netmask : %s\n", inet_ntoa(net->guess_ipdata.ip_netmask)); fprintf(txtfile, " IP Gateway : %s\n", inet_ntoa(net->guess_ipdata.ip_gateway)); } fprintf(txtfile, " Last BSSTS : %llu\n", (long long unsigned int) net->bss_timestamp); for (map<uuid, Netracker::source_data *>::iterator sdi = net->source_map.begin(); sdi != net->source_map.end(); ++sdi) { KisPacketSource *kps = globalreg->sourcetracker->FindKisPacketSourceUUID(sdi->second->source_uuid); if (kps == NULL) { fprintf(txtfile, " Seen By : (Deleted Source) %s %d packets\n", kps->FetchUUID().UUID2String().c_str(), sdi->second->num_packets); } else { fprintf(txtfile, " Seen By : %s (%s) %s %d packets\n", kps->FetchName().c_str(), kps->FetchInterface().c_str(), kps->FetchUUID().UUID2String().c_str(), sdi->second->num_packets); } fprintf(txtfile, " %.24s\n", ctime((const time_t *) &(sdi->second->last_seen))); } if (net->cdp_dev_id.length() > 0) fprintf(txtfile, " CDP Device : \"%s\"\n", net->cdp_dev_id.c_str()); if (net->cdp_port_id.length() > 0) fprintf(txtfile, " CDP Port : \"%s\"\n", net->cdp_port_id.c_str()); for (map<string, string>::const_iterator ai = net->arb_tag_map.begin(); ai != net->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; if (ai->first.length() <= 11) fprintf(txtfile, "%11.11s : \"%s\"\n", ai->first.c_str(), ai->second.c_str()); else fprintf(txtfile, "%s : \"%s\"\n", ai->first.c_str(), ai->second.c_str()); } // Sloppy iteration but it doesn't happen often and alert backlogs shouldn't // be that huge for (unsigned int an = 0; an < alerts->size(); an++) { if ((*alerts)[an]->bssid != net->bssid) continue; kis_alert_info *ali = (*alerts)[an]; fprintf(txtfile, " Alert : %.24s %s %s\n", ctime((const time_t *) &(ali->tm.tv_sec)), ali->header.c_str(), ali->text.c_str()); } int clinum = 0; // Get the client range pairs and print them out for (y = net->client_map.begin(); y != net->client_map.end(); ++y) { Netracker::tracked_client *cli = y->second; clinum++; if (cli->type == client_remove) continue; string ctype; switch (cli->type) { case client_fromds: ctype = "From Distribution"; break; case client_tods: ctype = "To Distribution"; break; case client_interds: ctype = "Inter-Distribution"; break; case client_established: ctype = "Established"; break; case client_adhoc: ctype = "Ad-hoc"; break; default: ctype = "Unknown"; break; } fprintf(txtfile, " Client %d: MAC %s\n", clinum, cli->mac.Mac2String().c_str()); fprintf(txtfile, " Manuf : %s\n", cli->manuf.c_str()); fprintf(txtfile, " First : %.24s\n", ctime(&(cli->first_time))); fprintf(txtfile, " Last : %.24s\n", ctime(&(cli->last_time))); fprintf(txtfile, " Type : %s\n", ctype.c_str()); fprintf(txtfile, " MAC : %s\n", cli->mac.Mac2String().c_str()); int ssidnum = 1; for (map<uint32_t, Netracker::adv_ssid_data *>::iterator m = cli->ssid_map.begin(); m != cli->ssid_map.end(); ++m) { string typestr; if (m->second->type == ssid_beacon) typestr = "Beacon"; else if (m->second->type == ssid_proberesp) typestr = "Probe Response"; else if (m->second->type == ssid_probereq) typestr = "Probe Request"; fprintf(txtfile, " SSID %d\n", ssidnum); fprintf(txtfile, " Type : %s\n", typestr.c_str()); if (m->second->ssid_cloaked) fprintf(txtfile, " SSID : <cloaked>\n"); else fprintf(txtfile, " SSID : %s\n", m->second->ssid.c_str()); if (m->second->beacon_info.length() > 0) fprintf(txtfile, " Info : %s\n", m->second->beacon_info.c_str()); fprintf(txtfile, " First : %.24s\n", ctime(&(m->second->first_time))); fprintf(txtfile, " Last : %.24s\n", ctime(&(m->second->last_time))); fprintf(txtfile, " Max Rate : %2.1f\n", m->second->maxrate); if (m->second->beaconrate != 0) fprintf(txtfile, " Beacon : %d\n", m->second->beaconrate); fprintf(txtfile, " Packets : %d\n", m->second->packets); if (m->second->dot11d_vec.size() > 0) { fprintf(txtfile, " Country : %s\n", m->second->dot11d_country.c_str()); for (unsigned int z = 0; z < m->second->dot11d_vec.size(); z++) { fprintf(txtfile, " Chan Range: %u-%u %u dBm\n", m->second->dot11d_vec[z].startchan, m->second->dot11d_vec[z].numchan, m->second->dot11d_vec[z].txpower); } } if (m->second->cryptset == 0) fprintf(txtfile, " Encryption : None\n"); if (m->second->cryptset & crypt_wep) fprintf(txtfile, " Encryption : WEP\n"); if (m->second->cryptset & crypt_layer3) fprintf(txtfile, " Encryption : Layer3\n"); if (m->second->cryptset & crypt_wep40) fprintf(txtfile, " Encryption : WEP40\n"); if (m->second->cryptset & crypt_wep104) fprintf(txtfile, " Encryption : WEP104\n"); if (m->second->cryptset & crypt_tkip) fprintf(txtfile, " Encryption : TKIP\n"); if (m->second->cryptset & crypt_wpa) fprintf(txtfile, " Encryption : WPA\n"); if (m->second->cryptset & crypt_psk) fprintf(txtfile, " Encryption : PSK\n"); if (m->second->cryptset & crypt_aes_ocb) fprintf(txtfile, " Encryption : AES-OCB\n"); if (m->second->cryptset & crypt_aes_ccm) fprintf(txtfile, " Encryption : AES-CCM\n"); if (m->second->cryptset & crypt_leap) fprintf(txtfile, " Encryption : LEAP\n"); if (m->second->cryptset & crypt_ttls) fprintf(txtfile, " Encryption : TTLS\n"); if (m->second->cryptset & crypt_tls) fprintf(txtfile, " Encryption : TLS\n"); if (m->second->cryptset & crypt_peap) fprintf(txtfile, " Encryption : PEAP\n"); if (m->second->cryptset & crypt_isakmp) fprintf(txtfile, " Encryption : ISAKMP\n"); if (m->second->cryptset & crypt_pptp) fprintf(txtfile, " Encryption : PPTP\n"); if (m->second->cryptset & crypt_fortress) fprintf(txtfile, " Encryption : Fortress\n"); if (m->second->cryptset & crypt_keyguard) fprintf(txtfile, " Encryption : Keyguard\n"); ssidnum++; } fprintf(txtfile, " Channel : %d\n", cli->channel); for (map<unsigned int, unsigned int>::const_iterator fmi = cli->freq_mhz_map.begin(); fmi != cli->freq_mhz_map.end(); ++fmi) { float perc = ((float) fmi->second / (float) (cli->llc_packets + cli->data_packets)) * 100; fprintf(txtfile, " Frequency : %d - %d packets, %.02f%%\n", fmi->first, fmi->second, perc); } fprintf(txtfile, " Max Seen : %d\n", cli->snrdata.maxseenrate * 100); if (cli->snrdata.carrierset & (1 << (int) carrier_80211b)) fprintf(txtfile, " Carrier : IEEE 802.11b\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211bplus)) fprintf(txtfile, " Carrier : IEEE 802.11b+\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211a)) fprintf(txtfile, " Carrier : IEEE 802.11a\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211g)) fprintf(txtfile, " Carrier : IEEE 802.11g\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211fhss)) fprintf(txtfile, " Carrier : IEEE 802.11 FHSS\n"); if (cli->snrdata.carrierset & (1 << (int) carrier_80211dsss)) fprintf(txtfile, " Carrier : IEEE 802.11 DSSS\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_cck)) fprintf(txtfile, " Encoding : CCK\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_pbcc)) fprintf(txtfile, " Encoding : PBCC\n"); if (cli->snrdata.encodingset & (1 << (int) encoding_ofdm)) fprintf(txtfile, " Encoding : OFDM\n"); fprintf(txtfile, " LLC : %d\n", cli->llc_packets); fprintf(txtfile, " Data : %d\n", cli->data_packets); fprintf(txtfile, " Crypt : %d\n", cli->crypt_packets); fprintf(txtfile, " Fragments : %d\n", cli->fragments); fprintf(txtfile, " Retries : %d\n", cli->retries); fprintf(txtfile, " Total : %d\n", cli->llc_packets + cli->data_packets); fprintf(txtfile, " Datasize : %llu\n", (long long unsigned int) cli->datasize); if (cli->gpsdata.gps_valid) { fprintf(txtfile, " Min Pos : Lat %f Lon %f Alt %f Spd %f\n", cli->gpsdata.min_lat, cli->gpsdata.min_lon, cli->gpsdata.min_alt, cli->gpsdata.min_spd); fprintf(txtfile, " Max Pos : Lat %f Lon %f Alt %f Spd %f\n", cli->gpsdata.max_lat, cli->gpsdata.max_lon, cli->gpsdata.max_alt, cli->gpsdata.max_spd); fprintf(txtfile, " Peak Pos : Lat %f Lon %f Alt %f\n", cli->snrdata.peak_lat, cli->snrdata.peak_lon, cli->snrdata.peak_alt); fprintf(txtfile, " Avg Pos : AvgLat %f AvgLon %f AvgAlt %f\n", cli->gpsdata.aggregate_lat, cli->gpsdata.aggregate_lon, cli->gpsdata.aggregate_alt); } if (cli->guess_ipdata.ip_type > ipdata_factoryguess && cli->guess_ipdata.ip_type < ipdata_group) { string iptype; switch (cli->guess_ipdata.ip_type) { case ipdata_udptcp: iptype = "UDP/TCP"; break; case ipdata_arp: iptype = "ARP"; break; case ipdata_dhcp: iptype = "DHCP"; break; default: iptype = "Unknown"; break; } fprintf(txtfile, " IP Type : %s\n", iptype.c_str()); fprintf(txtfile, " IP Block : %s\n", inet_ntoa(cli->guess_ipdata.ip_addr_block)); fprintf(txtfile, " IP Netmask : %s\n", inet_ntoa(cli->guess_ipdata.ip_netmask)); fprintf(txtfile, " IP Gateway : %s\n", inet_ntoa(cli->guess_ipdata.ip_gateway)); } for (map<uuid, Netracker::source_data *>::iterator sdi = cli->source_map.begin(); sdi != cli->source_map.end(); ++sdi) { KisPacketSource *kps = globalreg->sourcetracker->FindKisPacketSourceUUID(sdi->second->source_uuid); if (kps == NULL) { fprintf(txtfile, " Seen By : (Deleted Source) %s %d packets\n", kps->FetchUUID().UUID2String().c_str(), sdi->second->num_packets); } else { fprintf(txtfile, " Seen By : %s (%s) %s %d packets\n", kps->FetchName().c_str(), kps->FetchInterface().c_str(), kps->FetchUUID().UUID2String().c_str(), sdi->second->num_packets); } fprintf(txtfile, " %.24s\n", ctime((const time_t *) &(sdi->second->last_seen))); } if (cli->cdp_dev_id.length() > 0) fprintf(txtfile, " CDP Device : \"%s\"\n", cli->cdp_dev_id.c_str()); if (cli->cdp_port_id.length() > 0) fprintf(txtfile, " CDP Port : \"%s\"\n", cli->cdp_port_id.c_str()); if (cli->dhcp_host.length() > 0) fprintf(txtfile, " DHCP Host : \"%s\"\n", cli->dhcp_host.c_str()); if (cli->dhcp_vendor.length() > 0) fprintf(txtfile, " DHCP OS : \"%s\"\n", cli->dhcp_vendor.c_str()); for (map<string, string>::const_iterator ai = cli->arb_tag_map.begin(); ai != cli->arb_tag_map.end(); ++ai) { if (ai->first == "" || ai->second == "") continue; if (ai->first.length() <= 12) fprintf(txtfile, "%12.12s : \"%s\"\n", ai->first.c_str(), ai->second.c_str()); else fprintf(txtfile, "%s : \"%s\"\n", ai->first.c_str(), ai->second.c_str()); } } } fflush(txtfile); fclose(txtfile); txtfile = NULL; if (rename(tempname.c_str(), fname.c_str()) < 0) { _MSG("Failed to rename nettxt temp file " + tempname + " to " + fname + ":" + string(strerror(errno)), MSGFLAG_ERROR); return -1; } dumped_frames = netnum; return 1; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/packetsource_drone.h�������������������������������������������������������������0000664�0001750�0001750�00000014113�12124602454�017503� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKETSOURCE_DRONE_H__ #define __PACKETSOURCE_DRONE_H__ /* Drone client * * This forms the heart of the drone client system which gets packets from a * remote source. * * The actual packetsource functions as a simple stub which creates and * destroys the ClientFramework-derived DroneClientFrame. DroneClientFrame * handles all of the processing and injection. */ #include "config.h" #include "packet.h" #include "packetsource.h" #include "packetchain.h" #include "gpscore.h" #include "kis_droneframe.h" #include "clinetframework.h" #include "tcpclient.h" #include "packetsourcetracker.h" #define USE_PACKETSOURCE_DRONE int droneclienttimer_hook(TIMEEVENT_PARMS); class DroneClientFrame : public ClientFramework { public: DroneClientFrame(); DroneClientFrame(GlobalRegistry *in_globalreg); virtual ~DroneClientFrame(); virtual void SetPacketsource(void *in_src); virtual int OpenConnection(string in_conparm, int in_recon); virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { if (netclient == NULL) return in_max_fd; return netclient->MergeSet(in_max_fd, out_rset, out_wset); } virtual int Poll(fd_set &in_rset, fd_set& in_wset); virtual int ParseData(); virtual int KillConnection(); virtual int Shutdown(); virtual int time_handler(); int SendPacket(drone_packet *in_pack); int SendChannelData(pst_packetsource *in_src, unsigned int in_cmd); void SourceActionHandler(pst_packetsource *src, int action, int flags); virtual int Reconnect(); virtual void ConnectCB(int status); protected: TcpClient *tcpcli; int reconnect; time_t last_disconnect; time_t last_frame; int cli_type; int cli_port; char cli_host[129]; void *packetsource; int timerid; string remote_name; map<uuid, int> virtual_src_map; }; class PacketSource_Drone : public KisPacketSource { public: PacketSource_Drone() { fprintf(stderr, "FATAL OOPS: Packetsource_Drone() called\n"); exit(1); } PacketSource_Drone(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector<opt_pair> *in_opts) { return new PacketSource_Drone(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device) { if (in_device == "drone") { type = "drone"; return 1; } return 0; } virtual int RegisterSources(Packetsourcetracker *tracker); // Standard interface for capturesource PacketSource_Drone(GlobalRegistry *in_globalreg, string in_interface, vector<opt_pair> *in_opts); virtual ~PacketSource_Drone(); virtual int OpenSource(); virtual int CloseSource(); // No meaning on the drone master source virtual int EnableMonitor() { return 0; } virtual int DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_SILENCE; } virtual int SetChannel(unsigned int in_ch) { return 0; } virtual int FetchChannel() { return 0; } virtual int FetchDescriptor(); virtual int Poll(); protected: virtual void FetchRadioData(kis_packet *in_packet); DroneClientFrame *droneframe; int reconnect; string connecturl; }; // Virtual packet source that inherits the UUID and characteristics of a capture // source on a remote drone. All channel controls are pumped through to the drone // source. Packets from the drone remotes will show up from sources based off // this. class PacketSource_DroneRemote : public KisPacketSource { public: PacketSource_DroneRemote() { fprintf(stderr, "FATAL OOPS: Packetsource_DroneRemote() called\n"); exit(1); } PacketSource_DroneRemote(GlobalRegistry *in_globalreg) : KisPacketSource(in_globalreg) { } virtual KisPacketSource *CreateSource(GlobalRegistry *in_globalreg, string in_interface, vector<opt_pair> *in_opts) { return new PacketSource_DroneRemote(in_globalreg, in_interface, in_opts); } virtual int AutotypeProbe(string in_device) { return 0; } virtual int RegisterSources(Packetsourcetracker *tracker); PacketSource_DroneRemote(GlobalRegistry *in_globalreg, string in_interface, vector<opt_pair> *in_opts) : KisPacketSource(in_globalreg, in_interface, in_opts) { droneframe = NULL; rem_channelcapable = 0; } virtual ~PacketSource_DroneRemote(); // Open and close have no effect virtual int OpenSource() { return 0; } virtual int CloseSource() { return 0; } // Return remote capability virtual int FetchChannelCapable() { return rem_channelcapable; } // Drop-through commands to drone virtual int SetChannel(unsigned int in_ch); virtual int FetchChannel(); // Stuff we can't implement virtual int EnableMonitor() { return 0; } virtual int DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_SILENCE; } // Skip channel hop virtual int FetchSkipChanhop() { return 1; } // Local stuff virtual int FetchDescriptor() { return -1; } virtual int Poll() { return 0; } // Special functions to let the drone framework spawn and control us virtual int SetDroneFrame(DroneClientFrame *in_frame) { droneframe = in_frame; return 1; } virtual int SetUUID(uuid in_uuid) { src_uuid = in_uuid; return 1; } virtual void IncrementNumPackets() { num_packets++; } virtual void SetPST(pst_packetsource *in_pst) { pstsource = in_pst; } protected: virtual void FetchRadioData(kis_packet *in_packet) { } int rem_channelcapable; DroneClientFrame *droneframe; pst_packetsource *pstsource; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/ipc_remote.cc��������������������������������������������������������������������0000664�0001750�0001750�00000062530�12124602454�016116� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <stdio.h> #include <time.h> #include <list> #include <map> #include <vector> #include <algorithm> #include <string> #include <sstream> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include "ipc_remote.h" void IPC_MessageClient::ProcessMessage(string in_msg, int in_flags) { // Build it into a msgbus ipc block ... is there a smarter way to // build these things? ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet) + 8 + in_msg.length() + 1); ipc_msgbus_pass *msgb = (ipc_msgbus_pass *) pack->data; msgb->msg_flags = in_flags; msgb->msg_len = in_msg.length() + 1; snprintf(msgb->msg, msgb->msg_len, "%s", in_msg.c_str()); pack->data_len = 8 + in_msg.length() + 1; pack->ipc_cmdnum = MSG_CMD_ID; pack->ipc_ack = 0; #if 0 // Don't treat fatal as shutdown // // If it's a fatal frame, push it as a shutdown if ((in_flags & MSGFLAG_FATAL)) { ((IPCRemote *) auxptr)->ShutdownIPC(pack); return; } #endif // Push it via the IPC ((IPCRemote *) auxptr)->SendIPC(pack); // It gets freed once its sent so don't free it ourselves here } int ipc_msg_callback(IPC_CMD_PARMS) { (void) auxptr; // Child IPC does nothing with a MSG frame if (parent == 0) return 0; // Blow up on short IPC if (len < 5) { _MSG("IPC messagebus handler got a short message block", MSGFLAG_ERROR); return -1; } // Strip it apart and inject it into the message bus ipc_msgbus_pass *pass = (ipc_msgbus_pass *) data; _MSG(pass->msg, pass->msg_flags); return 0; } int ipc_die_callback(IPC_CMD_PARMS) { (void) data; (void) len; // Child receiving DIE command shuts down if (parent == 0) { // Call the internal shutdown process ((IPCRemote *) auxptr)->IPCDie(); // Exit entirely, if we didn't already exit(0); } // Parent receiving DIE command knows child is dieing for some // reason, send a message note, we'll figure out later if this is // fatal ostringstream osstr; osstr << "IPC controller got notification that IPC child process " << (int) ((IPCRemote *) auxptr)->FetchSpawnPid() << " is shutting down."; _MSG(osstr.str(), MSGFLAG_INFO); // Call the internal die sequence to make sure the child pid goes down ((IPCRemote *) auxptr)->IPCDie(); return 0; } int ipc_sync_callback(IPC_CMD_PARMS) { // Parent does nothing if (parent == 1) return 0; if (len < (int) sizeof(ipc_sync)) { _MSG("IPC sync handler got a short sync block", MSGFLAG_ERROR); return -1; } ((IPCRemote *) auxptr)->SyncIPCCmd((ipc_sync *) data); return 0; } IPCRemote::IPCRemote() { fprintf(stderr, "FATAL OOPS: IPCRemote called w/ no globalreg\n"); exit(1); } IPCRemote::IPCRemote(GlobalRegistry *in_globalreg, string in_procname) { globalreg = in_globalreg; procname = in_procname; if (globalreg->messagebus == NULL) { fprintf(stderr, "FATAL OOPS: IPCRemote called before messagebus\n"); exit(1); } child_exec_mode = 0; next_cmdid = 0; ipc_pid = -1; ipc_spawned = 0; ipc_synced = 0; exit_errno = 0; // Register builtin commands (in proper order!) RegisterIPCCmd(&ipc_die_callback, NULL, this, "DIE"); RegisterIPCCmd(&ipc_msg_callback, NULL, this, "MSG"); RegisterIPCCmd(&ipc_sync_callback, NULL, this, "SYNC"); globalreg->RegisterPollableSubsys(this); } IPCRemote::~IPCRemote() { globalreg->RemovePollableSubsys(this); } int IPCRemote::CheckPidVec() { // printf("debug - checkpidvec ipc_pid %d\n", ipc_pid); if (ipc_pid == 0) return 0; for (unsigned int x = 0; x < globalreg->sigchild_vec.size(); x++) { if (globalreg->sigchild_vec[x].pid == ipc_pid) { // printf("debug - check pid vec found pid %d status %d\n", ipc_pid, globalreg->sigchild_vec[x].status); CatchSigChild(globalreg->sigchild_vec[x].status); globalreg->sigchild_vec.erase(globalreg->sigchild_vec.begin() + x); return -1; } } return 0; } int IPCRemote::SyncIPCCmd(ipc_sync *data) { // Handle the end-of-sync command if (data->ipc_cmdnum == 0) { for (map<unsigned int, ipc_cmd_rec *>::iterator x = ipc_sync_map.begin(); x != ipc_sync_map.end(); ++x) { IPCmdCallback cback = x->second->callback; if (cback != NULL) (*cback)(globalreg, NULL, 0, x->second->auxptr, 0); } ipc_synced = 1; return 1; } // Search the map for something of this name for (map<unsigned int, ipc_cmd_rec *>::iterator x = ipc_cmd_map.begin(); x != ipc_cmd_map.end(); ++x) { ipc_cmd_rec *cr = x->second; string name = (char *) data->name; if (cr->name == name) { cr->id = data->ipc_cmdnum; ipc_cmd_map[data->ipc_cmdnum] = cr; ipc_cmd_map.erase(x); return 1; } } return 1; } int IPCRemote::SetChildExecMode(int argc, char *argv[]) { int tint; // Set us to child mode ipc_pid = 0; // Set our next cmd id to something big and negative, so that we can // stock cmds prior to a sync, but not interfere once the sync begins next_cmdid = -4098; child_exec_mode = 1; // Parse the FD out if (argc < 2) { globalreg->fatal_condition = 1; return -1; } if (sscanf(argv[1], "%d", &tint) != 1) { globalreg->fatal_condition = 1; return -1; } child_cmd = string(argv[0]); sockpair[0] = tint; ipc_spawned = 1; ipc_pid = 0; return 1; } int IPCRemote::RegisterIPCCmd(IPCmdCallback in_callback, IPCmdCallback discard_ackback, void *in_aux, string in_name) { // Allow registering commands after spawning if we're running a child command // since we can post-spawn sync if (ipc_spawned && child_cmd == "") { _MSG("IPC_Remote - Tried to register a command after the IPC agent has " "been spawned. Commands must be registered before Spawn().", MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Look for the callback already in the system for (map<unsigned int, ipc_cmd_rec *>::iterator x = ipc_cmd_map.begin(); x != ipc_cmd_map.end(); ++x) { if (x->second->callback == in_callback && x->second->name == in_name) return x->first; } next_cmdid++; ipc_cmd_rec *rec = new ipc_cmd_rec; rec->auxptr = in_aux; rec->callback = in_callback; rec->name = in_name; rec->id = next_cmdid; // Push the sync complete callbacks into their own map if (in_name == "SYNCCOMPLETE") { ipc_sync_map[next_cmdid] = rec; } else { ipc_cmd_map[next_cmdid] = rec; } // printf("debug - %d registered cmd %s %d\n", getpid(), in_name.c_str(), next_cmdid); return next_cmdid; } int IPCRemote::SpawnIPC() { // Don't build the socket pair if we're in exec child mode if (child_exec_mode == 0) { // Generate the socket pair before the split if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockpair) < 0) { _MSG("Unable to great socket pair for IPC communication: " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } unsigned int socksize = 32768; setsockopt(sockpair[0], SOL_SOCKET, SO_SNDBUF, &socksize, sizeof(socksize)); setsockopt(sockpair[1], SOL_SOCKET, SO_SNDBUF, &socksize, sizeof(socksize)); // Fork and launch the child control loop & set up the rest of our internal // info. if ((ipc_pid = fork()) < 0) { // If we fail we're still in the pid-space of the starting process and // we can set this cleanly _MSG("Unable to fork() and create child process for IPC communication: " + string(strerror(errno)), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // Split into the IPC child control loop if we've forked if (ipc_pid == 0) { signal(SIGINT, SIG_DFL); signal(SIGKILL, SIG_DFL); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); // Close our copy of the other half close(sockpair[1]); // Write a single byte on the FD to sync us if (write(sockpair[0], &(sockpair[0]), 1) < 1) { exit(1); } // Run the client binary if we have one if (child_cmd != "") { char **cmdarg = new char *[3]; cmdarg[0] = strdup(child_cmd.c_str()); cmdarg[1] = new char[4]; cmdarg[2] = NULL; snprintf(cmdarg[1], 4, "%d", sockpair[0]); // We're running as the child here, we have to pass this failure // up in the return value and this doesn't cause an immediate exit // with error for the caller... if (execve(cmdarg[0], cmdarg, NULL) < 0) { int status = errno; string fail = "Failed to launch IPC child: " + string(strerror(status)); ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet) + 8 + fail.length() + 1); ipc_msgbus_pass *msgb = (ipc_msgbus_pass *) pack->data; msgb->msg_flags = MSGFLAG_FATAL; msgb->msg_len = fail.length() + 1; snprintf(msgb->msg, msgb->msg_len, "%s", fail.c_str()); pack->data_len = 8 + fail.length() + 1; pack->ipc_cmdnum = MSG_CMD_ID; pack->ipc_ack = 0; exit_errno = status; ShutdownIPC(pack); } } IPC_Child_Loop(); exit(0); } // Close the parent half of the socket pair close(sockpair[0]); // Blocking read the sync byte char sync; if (read(sockpair[1], &sync, 1) < 1) return -1; } // We've spawned, can't set new commands anymore ipc_spawned = 1; return 1; } int IPCRemote::SyncIPC() { // If we spawned something that needs to be synced, send all our protocols if (child_cmd != "") { for (map<unsigned int, ipc_cmd_rec *>::iterator x = ipc_cmd_map.begin(); x != ipc_cmd_map.end(); ++x) { if (x->first < LAST_BUILTIN_CMD_ID) continue; ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_sync)); ipc_sync *sync = (ipc_sync *) pack->data; sync->ipc_cmdnum = x->first; snprintf((char *) sync->name, 32, "%s", x->second->name.c_str()); pack->data_len = sizeof(ipc_sync); pack->ipc_cmdnum = SYNC_CMD_ID; pack->ipc_ack = 0; // Push it via the IPC SendIPC(pack); } } // Send a cmdid 0 to indicate the end of sync ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet) + sizeof(ipc_sync)); ipc_sync *sync = (ipc_sync *) pack->data; sync->ipc_cmdnum = 0; sync->name[0] = '\0'; pack->data_len = sizeof(ipc_sync); pack->ipc_cmdnum = SYNC_CMD_ID; pack->ipc_ack = 0; SendIPC(pack); return 1; } int IPCRemote::ShutdownIPC(ipc_packet *pack) { /* if (ipc_spawned <= 0) return 0; */ int sock; if (ipc_pid == 0) { sock = sockpair[0]; } else { sock = sockpair[1]; } // If we have a last frame, send it if (pack != NULL) { pack->sentinel = IPCRemoteSentinel; send(sock, pack, sizeof(ipc_packet) + pack->data_len, 0); } // Nothing special here, just a die frame. Beauty is, we don't care // if we're the parent of the child, a clean shutdown will signal the other // side it's time to shuffle off ipc_packet *dpack = (ipc_packet *) malloc(sizeof(ipc_packet)); dpack->data_len = 0; dpack->ipc_cmdnum = DIE_CMD_ID; dpack->ipc_ack = 0; dpack->sentinel = IPCRemoteSentinel; // Send it immediately send(sock, dpack, sizeof(ipc_packet) + dpack->data_len, 0); // Die fully IPCDie(); return 1; } int IPCRemote::SendIPC(ipc_packet *pack) { // This is really just an enqueue system pack->sentinel = IPCRemoteSentinel; cmd_buf.push_back(pack); return 1; } int IPCRemote::FetchReadyState() { int p = CheckPidVec(); if (p < 0) { return p; } if (ipc_spawned == 0) { // printf("debug - %d not spawned\n", getpid()); return -1; } if (cmd_buf.size() != 0) { // printf("debug - %d buf size\n", getpid()); return 0; } return 1; } void IPCRemote::IPC_Child_Loop() { fd_set rset, wset; // Obviously we're spawned ipc_spawned = 1; // Close the other half of the socket pair close(sockpair[1]); // Kluge in a new message bus to talk to our parent and give it only // the IPC client to replicate messages globalreg->messagebus = new MessageBus; IPC_MessageClient *ipcmc = new IPC_MessageClient(globalreg, this); globalreg->messagebus->RegisterClient(ipcmc, MSGFLAG_ALL); // ignore a bunch of signals signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); // Set the process title init_proc_title(globalreg->argc, globalreg->argv, globalreg->envp); set_proc_title("%s", procname.c_str()); while (1) { int max_fd = 0; FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(sockpair[0], &rset); max_fd = sockpair[0]; // Do we have data to send? if (cmd_buf.size() > 0) { FD_SET(sockpair[0], &wset); } struct timeval tm; tm.tv_sec = 1; tm.tv_usec = 0; // Timeout after 1 second if we stopped getting commands if (select(max_fd + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { // Die violently fprintf(stderr, "FATAL OOPS: IPC command child %d got select() " "error and cannot continue cleanly: %s\n", getpid(), strerror(errno)); exit(1); } } // Handle in/out data if (Poll(rset, wset) < 0 || globalreg->fatal_condition) { exit(0); } } } void IPCRemote::IPCDie() { if (ipc_pid < 0) return; // If we're the child... if (ipc_pid == 0) { if (sockpair[0] >= 0) { // Shut down the child socket fd close(sockpair[0]); sockpair[0] = -1; } // and exit, we're done exit(exit_errno); } // otherwise if we're the parent... // Shut down the socket if (sockpair[1] >= 0) { close(sockpair[1]); sockpair[1] = -1; } // Wait for the child process to be dead _MSG("IPC controller waiting for IPC child process " + IntToString((int) ipc_pid) + " to end.", MSGFLAG_INFO); int dead = 0; int res = 0; for (unsigned int x = 0; x < 10; x++) { int w = waitpid(ipc_pid, &res, WNOHANG); // printf("debug - waitpid got %d wifexited %d\n", w, WIFEXITED(res)); if (w >= 0 && WIFEXITED(res)) { dead = 1; break; } usleep(100000); } if (!dead && ipc_pid > 0) { _MSG("Child process " + IntToString((int) ipc_pid) + " didn't die " "cleanly, killing it.", MSGFLAG_ERROR); kill(ipc_pid, SIGKILL); waitpid(ipc_pid, NULL, 0); } // Flush all the queued packets while (cmd_buf.size() > 0) { ipc_packet *pack = cmd_buf.front(); free(pack); cmd_buf.pop_front(); } _MSG("IPC controller IPC child process " + IntToString((int) ipc_pid) + " has ended.", MSGFLAG_INFO); ipc_spawned = 0; } int IPCRemote::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { int sock; // Don't call this on the child, we have a micro-select loop in the child // process... also do nothing if we haven't spawned yet. // int p = CheckPidVec(); // Let a forked child operate normally if ((ipc_pid == 0 && child_exec_mode == 0) || ipc_spawned <= 0 || p < 0) { // printf("debug - %d %p bailing on merge, ipc pid %d child mode %d spawned %d checkpid %d\n", getpid(), this, ipc_pid, child_exec_mode, ipc_spawned, p); return in_max_fd; } if (child_exec_mode) sock = sockpair[0]; else sock = sockpair[1]; // Set the socket to be read FD_SET(sock, out_rset); if (cmd_buf.size() > 0) { // printf("debug - %d cmd_buf set, flaggig write in merge\n", getpid()); FD_SET(sock, out_wset); } if (in_max_fd < sock) return sock; return in_max_fd; } int IPCRemote::Poll(fd_set& in_rset, fd_set& in_wset) { // This CAN be called by the parent or the child. In the parent it's called // by the normal pollable architecture. In the child we manually call it // from our micro-select loop. // printf("debug - %d poll queue %d\n", getpid(), cmd_buf.size()); int p = CheckPidVec(); if (ipc_spawned <= 0 || p < 0) { // printf("debug - %d %p not spawned / checkpid fail checkpid %d ipc %d\n", getpid(), this, p, ipc_spawned); return -1; } ostringstream osstr; int sock; if (ipc_pid == 0) sock = sockpair[0]; else sock = sockpair[1]; // Process packets out if (FD_ISSET(sock, &in_wset)) { // printf("debug - %d %p poll wset\n", getpid(), this); // Send as many frames as we have room for if we're not waiting for an ack while (cmd_buf.size() > 0 && ipc_spawned > 0) { ipc_packet *pack = cmd_buf.front(); // printf("debug - %d %p sending %d\n", getpid(), this, pack->ipc_cmdnum); // Send the frame if (send(sock, pack, sizeof(ipc_packet) + pack->data_len, 0) < 0) { if (errno == ENOBUFS || errno == EINTR || errno == EAGAIN) break; if (ipc_pid == 0) { // Blow up messily and spew into stderr fprintf(stderr, "IPC child %d got error writing packet to " "IPC socket: %s\n", getpid(), strerror(errno)); globalreg->fatal_condition = 1; return -1; } else { osstr << "IPC controller got error writing data to IPC socket " "for IPC child pid " << ipc_pid << ": " << strerror(errno); _MSG(osstr.str(), MSGFLAG_FATAL); ipc_spawned = -1; } } // Finally delete it cmd_buf.pop_front(); free(pack); } } else { // printf("debug - %d %p write not set in fd\n", getpid(), this); } // printf("dbeug - %d %p to rset\n", getpid(), this); // Process packets in if (FD_ISSET(sock, &in_rset)) { ipc_packet ipchdr; ipc_packet *fullpack = NULL; int ret = 0; // Peek at the packet header if ((ret = recv(sock, &ipchdr, sizeof(ipc_packet), MSG_PEEK)) < (int) sizeof(ipc_packet)) { if (ret < 0) { if (errno != EAGAIN && errno != EINTR) { // printf("debug - %d - failed recv %s\n", getpid(), strerror(errno)); if (ipc_pid == 0) osstr << "IPC child got error receiving packet header " "from controller: " << strerror(errno); else osstr << "IPC controller got error receiving packet header " "from IPC child pid " << ipc_pid << ": " << strerror(errno); _MSG(osstr.str(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } else { // printf("debug - %d - failed recv non-fatal - %s\n", getpid(), strerror(errno)); return 0; } } else { return 0; } } // Runt frame that's too small if (ret < (int) sizeof(ipc_packet)) return 0; // validate the ipc header if (ipchdr.sentinel != IPCRemoteSentinel) { // printf("debug - %d ipchdr sentiel ivalid %x != %x\n", getpid(), ipchdr.sentinel, IPCRemoteSentinel); if (ipc_pid == 0) osstr << "IPC child got error receiving packet header from " "controller: Invalid IPC sentinel value"; else osstr << "IPC controller got error receiving packet header " "from IPC child pid " << ipc_pid << ": Invalid IPC " "sentinel value"; _MSG(osstr.str(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } // See if its a command we understand map<unsigned int, ipc_cmd_rec *>::iterator cbitr = ipc_cmd_map.find(ipchdr.ipc_cmdnum); // printf("debug - IPC %d got ipc cmd %d ack %d\n", getpid(), ipchdr.ipc_cmdnum, ipchdr.ipc_ack); if (cbitr == ipc_cmd_map.end()) { // printf("debug - %d unknown cmd\n", getpid()); if (ipc_pid == 0) osstr << "IPC child got error receiving packet header from " "controller: Unknown IPC command"; else osstr << "IPC controller got error receiving packet header " "from IPC child pid " << ipc_pid << ": Unknown IPC command " << (int) ipchdr.ipc_cmdnum << " len " << ipchdr.data_len; _MSG(osstr.str(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } IPCmdCallback cback = cbitr->second->callback; void *cbackaux = cbitr->second->auxptr; // Get the full packet fullpack = (ipc_packet *) malloc(sizeof(ipc_packet) + ipchdr.data_len); if ((ret = recv(sock, fullpack, sizeof(ipc_packet) + ipchdr.data_len, 0)) < (int) sizeof(ipc_packet) + (int) ipchdr.data_len) { if (ret < 0) { if (ipc_pid == 0) osstr << "IPC child got error receiving packet " "from controller: " << strerror(errno); else osstr << "IPC controller got error receiving packet " "from IPC child pid " << ipc_pid << ": " << strerror(errno); _MSG(osstr.str(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } else { // printf("debug - %d got 0 reading full packet\n", getpid()); return 0; } } // If we've got a callback, process it if (cback != NULL) { // We "know" the rest is valid, so call the handler w/ this function. // giving it the ipc pid lets us cheat and tell if its the parent or not, // since the child has a 0 pid ret = (*cback)(globalreg, fullpack->data, fullpack->data_len, cbackaux, ipc_pid); if (ret < 0) { if (ipc_pid == 0) osstr << "IPC child got error executing command from controller."; else osstr << "IPC controller got error executing command " "from IPC child pid " << ipc_pid; _MSG(osstr.str(), MSGFLAG_FATAL); globalreg->fatal_condition = 1; return -1; } } free(fullpack); } return 1; } int ipc_fdpass_callback(IPC_CMD_PARMS) { if (parent == 1) return 0; return ((RootIPCRemote *) auxptr)->OpenFDPassSock(); } int ipc_rootipc_sync(IPC_CMD_PARMS) { ((RootIPCRemote *) auxptr)->RootIPCSynced(); return 1; } RootIPCRemote::RootIPCRemote(GlobalRegistry *in_globalreg, string procname) : IPCRemote(in_globalreg, procname) { root_ipc_synced = 0; SetChildCmd(string(BIN_LOC) + "/kismet_capture"); fdpass_cmd = RegisterIPCCmd(&ipc_fdpass_callback, NULL, this, "FDPASS"); rootipcsync_cmd = RegisterIPCCmd(&ipc_rootipc_sync, NULL, this, "ROOTSYNCED"); } int RootIPCRemote::FetchReadyState() { if (ipc_pid != 0 && root_ipc_synced == 0) { return 0; } return IPCRemote::FetchReadyState(); } int RootIPCRemote::ShutdownIPC(ipc_packet *packet) { ShutdownIPCPassFD(); return IPCRemote::ShutdownIPC(packet); } void RootIPCRemote::ShutdownIPCPassFD() { #ifdef SYS_LINUX char sockpath[32]; if (ipc_pid >= 0) { // Clean up the socket if it exists if (ipc_fd_fd >= 0) { snprintf(sockpath, 32, "/tmp/kisfdsock_%u", ipc_pid); close(ipc_fd_fd); ipc_fd_fd = -1; unlink(sockpath); } } ipc_fd_fd = -1; #endif } void RootIPCRemote::IPCDie() { if (ipc_pid != 0 && ipc_spawned > 0) { if (!globalreg->spindown) { _MSG("Root IPC control binary has died", MSGFLAG_FATAL); // globalreg->fatal_condition = 1; } } ShutdownIPCPassFD(); IPCRemote::IPCDie(); } int RootIPCRemote::OpenFDPassSock() { #ifdef SYS_LINUX char sockpath[32]; // Child creates it, since child probably has more privs if (ipc_pid != 0) { printf("debug - %d - child creating ipc fdfd\n", getpid()); snprintf(sockpath, 32, "/tmp/kisfdsock_%d", ipc_pid); // Unlink if it exists unlink(sockpath); unixsock.sun_family = AF_UNIX; strncpy(unixsock.sun_path, sockpath, sizeof(unixsock.sun_path)); if ((ipc_fd_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { _MSG("Failed to open socket to pass file descriptors: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } if (bind(ipc_fd_fd, (const struct sockaddr *) &unixsock, sizeof(unixsock))) { close(ipc_fd_fd); _MSG("Failed to bind socket to pass file descriptors: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } return ipc_fd_fd; } if ((ipc_fd_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { _MSG("Failed to open socket to pass file descriptors: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } unixsock.sun_family = AF_UNIX; snprintf(sockpath, 32, "/tmp/kisfdsock_%u", getpid()); strcpy(unixsock.sun_path, sockpath); return ipc_fd_fd; #endif return -1; } typedef struct { struct cmsghdr header; int fd; } __attribute__((packed)) cmsg_fd; int RootIPCRemote::SendDescriptor(int in_fd) { #ifdef SYS_LINUX struct msghdr msg; struct iovec vec[1]; cmsg_fd cm; // struct msghdr m; char str[1] = {'x'}; /* we have to send at least one byte */ vec[0].iov_base = str; vec[0].iov_len = sizeof(str); msg.msg_name = (struct sockaddr *) &unixsock; msg.msg_namelen = sizeof(unixsock); msg.msg_iov = vec; msg.msg_iovlen = 1; msg.msg_control = &cm; msg.msg_controllen = sizeof(cm); // m.msg_flags = 0; cm.header.cmsg_len = sizeof(cm); cm.header.cmsg_level = SOL_SOCKET; cm.header.cmsg_type = SCM_RIGHTS; cm.fd = in_fd; // printf("debug - %d child sending fd over fdfd\n", getpid()); if (sendmsg(ipc_fd_fd, &msg, 0) < 0) { _MSG("Root IPC file descriptor sendmsg() failed: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } return 1; #endif return -1; } int RootIPCRemote::ReceiveDescriptor() { #ifdef SYS_LINUX char buf[1]; struct msghdr m; struct iovec iov[1]; cmsg_fd cm; // printf("debug - %d receive descriptor\n", getpid()); if (ipc_fd_fd < 0) return -1; iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); memset(&m, 0, sizeof(m)); cm.header.cmsg_len = sizeof(cm); m.msg_iov = iov; m.msg_iovlen = 1; m.msg_control = &cm; m.msg_controllen = sizeof(cm); if (recvmsg(ipc_fd_fd, &m, 0) < 0) { _MSG("Root IPC failed to receive passed file descriptor: " + string(strerror(errno)), MSGFLAG_ERROR); return -1; } return cm.fd; #endif return -1; } int RootIPCRemote::SyncIPC() { if (ipc_pid != 0) { // Open the passing socket we made when we spawned the child if (OpenFDPassSock() < 0) { _MSG("Failed to open file descriptor passing socket during root IPC " "synchronization, may cause problems in the future", MSGFLAG_ERROR); } } return IPCRemote::SyncIPC(); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/netframework.cc������������������������������������������������������������������0000664�0001750�0001750�00000020574�12124602454�016476� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "netframework.h" NetworkServer::NetworkServer() { fprintf(stderr, "*** NetworkServer() not called with global registry\n"); } NetworkServer::NetworkServer(GlobalRegistry *in_reg) { globalreg = in_reg; sv_valid = 0; serv_fd = 0; max_fd = 0; srvframework = NULL; } int NetworkServer::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) { int max; if (in_max_fd < max_fd) { max = max_fd; } else { max = in_max_fd; } // Set the server fdif we're not in spindown, if we are spinning down, // stop listening and shut down if (globalreg->spindown && serv_fd >= 0) { close(serv_fd); serv_fd = -1; } else if (serv_fd >= 0) { FD_SET(serv_fd, out_rset); } for (int x = 0; x <= max; x++) { // Incoming read or our own clients if (FD_ISSET(x, &server_fdset)) FD_SET(x, out_rset); // Incoming write or any clients with a pending write ring if (write_buf_map.find(x) != write_buf_map.end() && write_buf_map[x]->FetchLen() > 0) FD_SET(x, out_wset); } return max; } int NetworkServer::Poll(fd_set& in_rset, fd_set& in_wset) { int ret; if (!sv_valid) return -1; // Look for new connections we need to accept int accept_fd = 0; if (serv_fd >= 0 && FD_ISSET(serv_fd, &in_rset)) { // Accept an inbound connection. This is non-fatal if it fails if ((accept_fd = Accept()) < 0) return 0; // Validate them and see if they're allowed to remain // Bounce back a 0 so we can log the refusal if (Validate(accept_fd) < 0) { KillConnection(accept_fd); return 0; } // Pass them to the framework accept if (srvframework->Accept(accept_fd) < 0) { KillConnection(accept_fd); return 0; } } // Handle input and output, dispatching to our other functions so we can // be overridden for (int x = 0; x <= max_fd; x++) { // Handle reading data. Accept() should have made them a // ringbuffer. if (FD_ISSET(x, &in_rset) && FD_ISSET(x, &server_fdset)) { if ((ret = ReadBytes(x)) < 0) { KillConnection(x); continue; } // Try to parse it. We only do this when its changed since // if it couldn't parse a fragment before it's not going to be // able to parse a fragment still if (ret > 0 && srvframework->ParseData(x) < 0) { KillConnection(x); continue; } } // Handle writing data. The write FD would never have gotten set // for checking if there wasn't data in the ring buffer, so we don't // have to check for that. if (FD_ISSET(x, &in_wset) && FD_ISSET(x, &server_fdset)) { if ((ret = WriteBytes(x)) < 0) continue; } } return 1; } int NetworkServer::FlushRings() { if (!sv_valid) return -1; if (FetchNumClients() < 1) return 0; fd_set rset, wset; int max; // Use a large granularity 2-second timer, what the hell time_t flushtime = time(0); // Nuke the fatal conditon so we can track our own failures int old_fcon = globalreg->fatal_condition; globalreg->fatal_condition = 0; while ((time(0) - flushtime) < 2) { // See if we have any data in any of our ring buffers int allflushed = 1; for (map<int, RingBuffer *>::iterator x = write_buf_map.begin(); x != write_buf_map.end(); ++x) { if (x->second->FetchLen() > 0) { allflushed = 0; break; } } if (allflushed) return 1; max = 0; FD_ZERO(&rset); FD_ZERO(&wset); max = MergeSet(max, &rset, &wset); struct timeval tm; tm.tv_sec = 0; tm.tv_usec = 100000; if (select(max + 1, &rset, &wset, NULL, &tm) < 0) { if (errno != EINTR && errno != EAGAIN) { globalreg->fatal_condition = 1; return -1; } } if (Poll(rset, wset) < 0 || globalreg->fatal_condition != 0) return -1; } globalreg->fatal_condition = old_fcon; return 1; } void NetworkServer::KillConnection(int in_fd) { // Let the framework clear any state info srvframework->KillConnection(in_fd); if (in_fd < 0) return; // Nuke descriptors FD_CLR(in_fd, &server_fdset); FD_CLR(in_fd, &pending_readset); // Nuke ringbuffers map<int, RingBuffer *>::iterator miter = read_buf_map.find(in_fd); if (miter != read_buf_map.end()) { delete read_buf_map[in_fd]; read_buf_map.erase(miter); } miter = write_buf_map.find(in_fd); if (miter != write_buf_map.end()) { delete write_buf_map[in_fd]; write_buf_map.erase(miter); } } int NetworkServer::WriteData(int in_clid, void *in_data, int in_len) { if (write_buf_map.find(in_clid) == write_buf_map.end()) { snprintf(errstr, STATUS_MAX, "NetworkServer::WriteData called with invalid " "client ID %d", in_clid); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } RingBuffer *write_buf = write_buf_map[in_clid]; if (write_buf->InsertDummy(in_len) == 0) { /* snprintf(errstr, STATUS_MAX, "NetworkServer::WriteData no room in ring " "buffer to insert %d bytes for client id %d", in_len, in_clid); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); */ return -2; } write_buf->InsertData((uint8_t *) in_data, in_len); return 1; } int NetworkServer::FetchReadLen(int in_clid) { if (read_buf_map.find(in_clid) == read_buf_map.end()) { snprintf(errstr, STATUS_MAX, "NetworkServer::ReadDataLen called with " "invalid client ID %d", in_clid); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } RingBuffer *read_buf = read_buf_map[in_clid]; return (int) read_buf->FetchLen(); } int NetworkServer::ReadData(int in_clid, void *ret_data, int in_max, int *ret_len) { if (read_buf_map.find(in_clid) == read_buf_map.end()) { snprintf(errstr, STATUS_MAX, "NetworkServer::ReadDataLen called with " "invalid client ID %d", in_clid); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } RingBuffer *read_buf = read_buf_map[in_clid]; read_buf->FetchPtr((uint8_t *) ret_data, in_max, ret_len); return (*ret_len); } int NetworkServer::MarkRead(int in_clid, int in_readlen) { if (read_buf_map.find(in_clid) == read_buf_map.end()) { snprintf(errstr, STATUS_MAX, "NetworkServer::ReadDataLen called with " "invalid client ID %d", in_clid); globalreg->messagebus->InjectMessage(errstr, MSGFLAG_ERROR); return -1; } RingBuffer *read_buf = read_buf_map[in_clid]; read_buf->MarkRead(in_readlen); return 1; } int NetworkServer::FetchClientVector(vector<int> *ret_vec) { ret_vec->reserve(write_buf_map.size()); for (map<int, RingBuffer *>::iterator x = write_buf_map.begin(); x != write_buf_map.end(); ++x) ret_vec->push_back(x->first); return ret_vec->size(); } int ServerFramework::Shutdown() { // Initiate a shutdown of the components if (netserver != NULL) { netserver->FlushRings(); netserver->Shutdown(); } return 1; } int ServerFramework::BufferDrained(int in_fd) { (void) in_fd; return 0; } ������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/client-plugin-example/�����������������������������������������������������������0000775�0001750�0001750�00000000000�12124602454�017656� 5����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/client-plugin-example/Makefile���������������������������������������������������0000664�0001750�0001750�00000001207�12124602454�021316� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Kismet wireless sniffer VERSION_MAJOR = 2005 VERSION_MINOR = 00 VERSION_TINY = devel-newcore KIS_INC_DIR = ../ HOME = . CXX = g++ CC = gcc LD = g++ LDFLAGS = -shared -rdynamic LIBS = -lstdc++ CFLAGS = -fPIC CXXFLAGS = -fPIC -pthread -DVERSION_MAJOR=\"$(VERSION_MAJOR)\" -DVERSION_MINOR=\"$(VERSION_MINOR)\" -DVERSION_TINY=\"$(VERSION_TINY)\" -DTIMESTAMP=\"`cat TIMESTAMP`\" CPPFLAGS = -I/usr/include -I$(KIS_INC_DIR) PLUGOBJS = kcliplug.o kcliplugin.so: $(PLUGOBJS) $(LD) $(LDFLAGS) $(PLUGOBJS) -o kcliplugin.so $(LIBS) .c.o: $(CC) $(CFLAGS) -c $*.c -o $@ .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $*.cc -o $@ .SUFFIXES: .c .cc .o �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/client-plugin-example/kcliplug.cc������������������������������������������������0000664�0001750�0001750�00000002626�12124602454�022005� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <config.h> #include <stdio.h> #include <string.h> #include <globalregistry.h> #include <kis_panel_plugin.h> #include <kis_panel_frontend.h> #include <kis_panel_windows.h> // Menu event plugin int menu_callback(void *auxptr) { ((KisPanelPluginData *) auxptr)->kpinterface->RaiseAlert("Example", "Example plugin raising alert since \n" "you picked it from the menu.\n"); return 1; } // Init plugin gets called when plugin loads extern "C" { int panel_plugin_init(GlobalRegistry *globalreg, KisPanelPluginData *pdata) { _MSG("Loading kcli example plugin", MSGFLAG_INFO); pdata->mainpanel->AddPluginMenuItem("Example Plugin", menu_callback, pdata); return 1; } } ����������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/client-plugin-example/TIMESTAMP��������������������������������������������������0000664�0001750�0001750�00000000002�12124602454�021134� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/packet_ieee80211.h���������������������������������������������������������������0000664�0001750�0001750�00000020133�12124602454�016455� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PACKET_IEEE80211_H__ #define __PACKET_IEEE80211_H__ #include "config.h" #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #include "macaddr.h" #ifndef SSID_SIZE #define SSID_SIZE 32 #endif #ifndef BEACON_INFO_LEN #define BEACON_INFO_LEN 128 #endif // packet conversion and extraction utilities // Packet types, these should correspond to the frame header types enum ieee_80211_type { packet_noise = -2, // We're too short or otherwise corrupted packet_unknown = -1, // What are we? packet_management = 0, // LLC management packet_phy = 1, // Physical layer packets, most drivers can't provide these packet_data = 2 // Data frames }; // Subtypes are a little odd because we re-use values depending on the type enum ieee_80211_subtype { packet_sub_unknown = -1, // Management subtypes packet_sub_association_req = 0, packet_sub_association_resp = 1, packet_sub_reassociation_req = 2, packet_sub_reassociation_resp = 3, packet_sub_probe_req = 4, packet_sub_probe_resp = 5, packet_sub_beacon = 8, packet_sub_atim = 9, packet_sub_disassociation = 10, packet_sub_authentication = 11, packet_sub_deauthentication = 12, // Phy subtypes packet_sub_pspoll = 10, packet_sub_rts = 11, packet_sub_cts = 12, packet_sub_ack = 13, packet_sub_cf_end = 14, packet_sub_cf_end_ack = 15, // Data subtypes packet_sub_data = 0, packet_sub_data_cf_ack = 1, packet_sub_data_cf_poll = 2, packet_sub_data_cf_ack_poll = 3, packet_sub_data_null = 4, packet_sub_cf_ack = 5, packet_sub_cf_ack_poll = 6, packet_sub_data_qos_data = 8, packet_sub_data_qos_data_cf_ack = 9, packet_sub_data_qos_data_cf_poll = 10, packet_sub_data_qos_data_cf_ack_poll = 11, packet_sub_data_qos_null = 12, packet_sub_data_qos_cf_poll_nod = 14, packet_sub_data_qos_cf_ack_poll = 15 }; // distribution directions enum ieee_80211_disttype { distrib_unknown, distrib_from, distrib_to, distrib_inter, distrib_adhoc }; // Signalling layer info - what protocol are we seeing data on? // Not all of these types are currently supported, of course enum phy_carrier_type { carrier_unknown, carrier_80211b, carrier_80211bplus, carrier_80211a, carrier_80211g, carrier_80211fhss, carrier_80211dsss, carrier_80211n20, carrier_80211n40 }; // Packet encoding info - how are packets encoded? enum phy_encoding_type { encoding_unknown, encoding_cck, encoding_pbcc, encoding_ofdm, encoding_dynamiccck, encoding_gfsk }; // Turbocell modes enum turbocell_type { turbocell_unknown, turbocell_ispbase, // 0xA0 turbocell_pollbase, // 0x80 turbocell_nonpollbase, // 0x00 turbocell_base // 0x40 }; // IAPP crypt enums enum iapp_type { iapp_announce_request = 0, iapp_announce_response = 1, iapp_handover_request = 2, iapp_handover_response = 3 }; enum iapp_pdu { iapp_pdu_ssid = 0x00, iapp_pdu_bssid = 0x01, iapp_pdu_oldbssid = 0x02, iapp_pdu_msaddr = 0x03, iapp_pdu_capability = 0x04, iapp_pdu_announceint = 0x05, iapp_pdu_hotimeout = 0x06, iapp_pdu_messageid = 0x07, iapp_pdu_phytype = 0x10, iapp_pdu_regdomain = 0x11, iapp_pdu_channel = 0x12, iapp_pdu_beaconint = 0x13, iapp_pdu_ouiident = 0x80, iapp_pdu_authinfo = 0x81 }; enum iapp_cap { iapp_cap_forwarding = 0x40, iapp_cap_wep = 0x20 }; enum iapp_phy { iapp_phy_prop = 0x00, iapp_phy_fhss = 0x01, iapp_phy_dsss = 0x02, iapp_phy_ir = 0x03, iapp_phy_ofdm = 0x04 }; enum iapp_dom { iapp_dom_fcc = 0x10, iapp_dom_ic = 0x20, iapp_dom_etsi = 0x30, iapp_dom_spain = 0x31, iapp_dom_france = 0x32, iapp_dom_mkk = 0x40 }; enum iapp_auth { iapp_auth_status = 0x01, iapp_auth_username = 0x02, iapp_auth_provname = 0x03, iapp_auth_rxpkts = 0x04, iapp_auth_txpkts = 0x05, iapp_auth_rxbytes = 0x06, iapp_auth_txbytes = 0x07, iapp_auth_logintime = 0x08, iapp_auth_timelimit = 0x09, iapp_auth_vollimit = 0x0a, iapp_auth_acccycle = 0x0b, iapp_auth_rxgwords = 0x0c, iapp_auth_txgwords = 0x0d, iapp_auth_ipaddr = 0x0e, iapp_auth_trailer = 0xff }; typedef struct { unsigned iapp_version : 8; unsigned iapp_type : 8; } __attribute__ ((packed)) iapp_header; typedef struct { unsigned pdu_type : 8; unsigned pdu_len : 16; } __attribute__ ((packed)) iapp_pdu_header; // Crypt bitfield enum crypt_type { crypt_none = 0, crypt_unknown = 1, crypt_wep = (1 << 1), crypt_layer3 = (1 << 2), // Derived from WPA headers crypt_wep40 = (1 << 3), crypt_wep104 = (1 << 4), crypt_tkip = (1 << 5), crypt_wpa = (1 << 6), crypt_psk = (1 << 7), crypt_aes_ocb = (1 << 8), crypt_aes_ccm = (1 << 9), //WPA Migration Mode crypt_wpa_migmode = (1 << 19), // Derived from data traffic crypt_leap = (1 << 10), crypt_ttls = (1 << 11), crypt_tls = (1 << 12), crypt_peap = (1 << 13), crypt_isakmp = (1 << 14), crypt_pptp = (1 << 15), crypt_fortress = (1 << 16), crypt_keyguard = (1 << 17), crypt_unknown_nonwep = (1 << 18), }; // Deciphering by casting. This is bad, and non portable, and we need to not // do it in the future but for now it'll work until we redo it with bitmanip #ifdef WORDS_BIGENDIAN // Byte ordering for bigendian systems. Bitwise strcts are so funky. typedef struct { unsigned short subtype : 4; unsigned short type : 2; unsigned short version : 2; unsigned short order : 1; unsigned short wep : 1; unsigned short more_data : 1; unsigned short power_management : 1; unsigned short retry : 1; unsigned short more_fragments : 1; unsigned short from_ds : 1; unsigned short to_ds : 1; } frame_control __attribute__ ((packed)); typedef struct { unsigned short frag : 12; unsigned short sequence : 4; } wireless_fragseq __attribute__ ((packed)); typedef struct { uint8_t timestamp[8]; // This field must be converted to host-endian before being used unsigned int beacon : 16; unsigned short agility : 1; unsigned short pbcc : 1; unsigned short short_preamble : 1; unsigned short wep : 1; unsigned short unused2 : 1; unsigned short unused1 : 1; unsigned short ibss : 1; unsigned short ess : 1; unsigned int coordinator : 8; } fixed_parameters __attribute__ ((packed)); #else // And 802.11 packet frame header typedef struct { unsigned short version : 2; unsigned short type : 2; unsigned short subtype : 4; unsigned short to_ds : 1; unsigned short from_ds : 1; unsigned short more_fragments : 1; unsigned short retry : 1; unsigned short power_management : 1; unsigned short more_data : 1; unsigned short wep : 1; unsigned short order : 1; } __attribute__ ((packed)) frame_control; typedef struct { unsigned short frag : 4; unsigned short sequence : 12; } __attribute__ ((packed)) wireless_fragseq; typedef struct { uint8_t timestamp[8]; // This field must be converted to host-endian before being used unsigned int beacon : 16; unsigned short ess : 1; unsigned short ibss : 1; unsigned short unused1 : 1; unsigned short unused2 : 1; unsigned short wep : 1; unsigned short short_preamble : 1; unsigned short pbcc : 1; unsigned short agility : 1; unsigned int coordinator : 8; } __attribute__ ((packed)) fixed_parameters; #endif #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/configfile.cc��������������������������������������������������������������������0000664�0001750�0001750�00000032165�12124602454�016076� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <string> #include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include "configfile.h" #include "util.h" int ConfigFile::ParseConfig(const char *in_fname) { FILE *configf; char confline[8192]; if ((configf = fopen(in_fname, "r")) == NULL) { fprintf(stderr, "ERROR: Reading config file '%s': %d (%s)\n", in_fname, errno, strerror(errno)); return -1; } while (!feof(configf)) { if (fgets(confline, 8192, configf) == NULL || feof(configf)) break; // It's easier to parse this using C++ functions string parsestr = StrStrip(confline); string directive, value; if (parsestr.length() == 0) continue; if (parsestr[0] == '#') continue; unsigned int eq; if ((eq = parsestr.find("=")) > parsestr.length()) { directive = parsestr; value = ""; } else { directive = StrStrip(parsestr.substr(0, eq)); value = StrStrip(parsestr.substr(eq+1, parsestr.length())); if (value == "") { fprintf(stderr, "ERROR: Illegal config option: %s\n", parsestr.c_str()); continue; } // Handling including files if (directive == "include") { printf("Including sub-config file: %s\n", value.c_str()); if (ParseConfig(value.c_str()) < 0) return -1; } else { config_map[StrLower(directive)].push_back(value); config_map_dirty[StrLower(directive)] = 1; } } } fclose(configf); return 1; } int ConfigFile::SaveConfig(const char *in_fname) { FILE *wf = NULL; if ((wf = fopen(in_fname, "w")) == NULL) { return -1; } for (map<string, vector<string> >::iterator x = config_map.begin(); x != config_map.end(); ++x) { for (unsigned int y = 0; y < x->second.size(); y++) { fprintf(wf, "%s=%s\n", x->first.c_str(), x->second[y].c_str()); } } fclose(wf); return 1; } string ConfigFile::FetchOpt(string in_key) { map<string, vector<string> >::iterator cmitr = config_map.find(StrLower(in_key)); // No such key if (cmitr == config_map.end()) return ""; // Get a single key if we can if (cmitr->second.size() == 0) return ""; string val = cmitr->second[0]; return val; } vector<string> ConfigFile::FetchOptVec(string in_key) { // Empty vec to return vector<string> eretvec; map<string, vector<string> >::iterator cmitr = config_map.find(StrLower(in_key)); // No such key if (cmitr == config_map.end()) return eretvec; return cmitr->second; } int ConfigFile::FetchOptBoolean(string in_key, int dvalue) { string v = StrLower(FetchOpt(in_key)); int r; r = StringToBool(v); if (r == -1) return dvalue; return r; } int ConfigFile::FetchOptDirty(string in_key) { if (config_map_dirty.find(StrLower(in_key)) == config_map_dirty.end()) return 0; return config_map_dirty[StrLower(in_key)]; } void ConfigFile::SetOptDirty(string in_key, int in_dirty) { config_map_dirty[StrLower(in_key)] = in_dirty; } void ConfigFile::SetOpt(string in_key, string in_val, int in_dirty) { vector<string> v; v.push_back(in_val); config_map[StrLower(in_key)] = v; SetOptDirty(in_key, in_dirty); } void ConfigFile::SetOptVec(string in_key, vector<string> in_val, int in_dirty) { config_map[StrLower(in_key)] = in_val; SetOptDirty(in_key, in_dirty); } // Expand a logfile into a full filename // Path/template from config // Logfile name to use // Logfile type to use // Starting number or desired number string ConfigFile::ExpandLogPath(string path, string logname, string type, int start, int overwrite) { string logtemplate; int inc = 0; logtemplate = path; for (unsigned int nl = logtemplate.find("%"); nl < logtemplate.length(); nl = logtemplate.find("%", nl)) { char op = logtemplate[nl+1]; logtemplate.erase(nl, 2); if (op == 'n') logtemplate.insert(nl, logname); else if (op == 'd') { time_t tnow; struct tm *now; tnow = time(0); now = localtime(&tnow); char datestr[24]; strftime(datestr, 24, "%b-%d-%Y", now); logtemplate.insert(nl, datestr); } else if (op == 'D') { time_t tnow; struct tm *now; tnow = time(0); now = localtime(&tnow); char datestr[24]; strftime(datestr, 24, "%Y%m%d", now); logtemplate.insert(nl, datestr); } else if (op == 't') { time_t tnow; struct tm *now; tnow = time(0); now = localtime(&tnow); char timestr[12]; strftime(timestr, 12, "%H-%M-%S", now); logtemplate.insert(nl, timestr); } else if (op == 'l') logtemplate.insert(nl, type.c_str()); else if (op == 'i') inc = nl; else if (op == 'h') { struct passwd *pw; pw = getpwuid(getuid()); if (pw == NULL) { fprintf(stderr, "ERROR: Could not explode home directory path, " "getpwuid() failed.\n"); exit(1); } logtemplate.insert(nl, pw->pw_dir); } else if (op == 'p') { string pfx = globalreg->log_prefix; if (pfx == "") pfx = FetchOpt("logprefix"); if (pfx != "") pfx += "/"; logtemplate.insert(nl, pfx); } } // If we've got an incremental, go back and find it and start testing if (inc) { int found = 0; if (start == 0) { // If we don't have a number we want to use, find the next free for (int num = 1; num < 100; num++) { string copied; struct stat filstat; // This is annoying char numstr[5]; snprintf(numstr, 5, "%d", num); copied = logtemplate; copied.insert(inc, numstr); copied += ".gz"; if (stat(copied.c_str(), &filstat) == 0) { continue; } copied = logtemplate; copied.insert(inc, numstr); copied += ".bz2"; if (stat(copied.c_str(), &filstat) == 0) { continue; } copied = logtemplate; copied.insert(inc, numstr); if (stat(copied.c_str(), &filstat) == 0) { continue; } // If we haven't been found with any of our variants, we're // clean, mark us found found = 1; logtemplate = copied; break; } } else { // Otherwise find out if this incremental is taken string copied; struct stat filstat; char numstr[5]; snprintf(numstr, 5, "%d", start); int localfound = 1; copied.insert(inc, numstr); copied = logtemplate; copied.insert(inc, numstr); copied += ".gz"; if (stat(copied.c_str(), &filstat) == 0 && overwrite != 0) { localfound = 0; } copied = logtemplate; copied.insert(inc, numstr); copied += ".bz2"; if (stat(copied.c_str(), &filstat) == 0 && overwrite != 0) { localfound = 0; } copied = logtemplate; copied.insert(inc, numstr); if (stat(copied.c_str(), &filstat) == 0 && overwrite != 0) { localfound = 0; } // If we haven't been found with any of our variants, we're // clean, mark us found found = localfound; if (localfound == 0) logtemplate = ""; else logtemplate = copied; } if (!found) { fprintf(stderr, "ERROR: Unable to find a logging file within 100 hits. " "If you really are logging this many times in 1 day, change " "log names or edit the source.\n"); exit(1); } } else { struct stat filstat; if (stat(logtemplate.c_str(), &filstat) != -1 && overwrite == 0) { logtemplate = ""; } } // Close the pwent endpwent(); return logtemplate; } uint32_t ConfigFile::FetchFileChecksum() { if (checksum == 0) CalculateChecksum(); return checksum; } void ConfigFile::CalculateChecksum() { string cks; for (map<string, vector<string> >::iterator x = config_map.begin(); x != config_map.end(); ++x) { cks += x->first; for (unsigned int y = 0; y < x->second.size(); y++) { cks += x->second[y]; } } checksum = Adler32Checksum(cks.c_str(), cks.length()); } int GroupConfigFile::ParseConfig(const char *in_fname) { FILE *configf; char confline[8192]; if ((configf = fopen(in_fname, "r")) == NULL) { fprintf(stderr, "ERROR: Reading grouped config file '%s': %s\n", in_fname, strerror(errno)); return -1; } root = new GroupEntity; root->name = ":root:"; vector<GroupEntity *> group_stack; group_stack.push_back(root); vector<GroupEntity *> primervec; parsed_group_map[root] = primervec; GroupEntity *sub = root; while (!feof(configf)) { if (fgets(confline, 8192, configf) == NULL) break; if (feof(configf)) break; string parsestr = StrStrip(confline); string directive, value; if (parsestr.length() == 0) continue; if (parsestr[0] == '#') continue; size_t eq; if ((eq = parsestr.find("=")) == string::npos) { // Look for a "foo {". { must be the end if (parsestr[parsestr.length() - 1] == '{') { directive = StrStrip(parsestr.substr(0, parsestr.length() - 1)); GroupEntity *newent = new GroupEntity; parsed_group_map[sub].push_back(newent); sub = newent; sub->name = directive; parsed_group_map[sub] = primervec; group_stack.push_back(sub); continue; } // Look for an ending }. Must be the first character, everything after // it is ignored if (parsestr[0] == '}') { if (sub == root) { fprintf(stderr, "ERROR: Unexpected closing '}'\n"); return -1; } group_stack.pop_back(); sub = group_stack.back(); continue; } } else { // Process a directive directive = StrStrip(parsestr.substr(0, eq)); value = StrStrip(parsestr.substr(eq + 1, parsestr.length())); if (value == "") { fprintf(stderr, "ERROR: Illegal config option: '%s'\n", parsestr.c_str()); continue; } if (directive == "include") { fprintf(stderr, "ERROR: Can't include sub-files right now\n"); return -1; } sub->value_map[StrLower(directive)].push_back(value); } } return 1; } string GroupConfigFile::FetchOpt(string in_key, GroupEntity *in_parent) { if (in_parent == NULL) in_parent = root; map<string, vector<string> >::iterator cmitr = in_parent->value_map.find(StrLower(in_key)); // No such key if (cmitr == in_parent->value_map.end()) return ""; // Get a single key if we can if (cmitr->second.size() == 0) return ""; string val = cmitr->second[0]; return val; } vector<string> GroupConfigFile::FetchOptVec(string in_key, GroupEntity *in_parent) { // Empty vec to return vector<string> eretvec; if (in_parent == NULL) in_parent = root; map<string, vector<string> >::iterator cmitr = in_parent->value_map.find(StrLower(in_key)); // No such key if (cmitr == in_parent->value_map.end()) return eretvec; return cmitr->second; } vector<GroupConfigFile::GroupEntity *> GroupConfigFile::FetchEntityGroup(GroupEntity *in_parent) { map<GroupEntity *, vector<GroupEntity *> >::iterator itr; if (in_parent == NULL) itr = parsed_group_map.find(root); else itr = parsed_group_map.find(in_parent); if (itr == parsed_group_map.end()) { vector<GroupEntity *> ret; return ret; } return itr->second; } uint32_t GroupConfigFile::FetchFileChecksum() { if (checksum == 0) CalculateChecksum(); return checksum; } void GroupConfigFile::CalculateChecksum() { string cks; map<GroupEntity *, vector<GroupEntity *> >::iterator x; for (x = parsed_group_map.begin(); x != parsed_group_map.end(); ++x) { for (unsigned int y = 0; y < x->second.size(); y++) { cks += x->second[y]->name; for (map<string, vector<string> >::iterator z = x->second[y]->value_map.begin(); z != x->second[y]->value_map.end(); ++z) { cks += z->first; for (unsigned int zz = 0; zz < z->second.size(); zz++) { cks += z->second[zz]; } } } } checksum = Adler32Checksum(cks.c_str(), cks.length()); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kismet-2013-03-R1b/macaddr.h������������������������������������������������������������������������0000664�0001750�0001750�00000042761�12124602454�015231� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __MACADDR_H__ #define __MACADDR_H__ #include "config.h" #include <stdio.h> #include <ctype.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <string.h> #include <signal.h> #include <unistd.h> #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #include <algorithm> #include <string> #include <vector> #include <map> #define MAC_LEN 6 #define MAC_STR_LEN ((MAC_LEN * 2) + 6) // Mac address transformed into 64bit int for fast sorting // Optional PHY encoding for multi-phy MAC collisions // Phy set assumes phy numbering starts at 1 (0 implies no phy set) // Setting a new mac clears the phy struct mac_addr { uint64_t longmac; uint64_t longmask; int error; // Convert a string mac address to the long-int storage format, with // mask conversion if present. void string2long(const char *in) { short unsigned int *bs_in = new short unsigned int[MAC_LEN]; error = 0; longmac = 0; longmask = (uint64_t) -1; // Get the MAC if (sscanf(in, "%hX:%hX:%hX:%hX:%hX:%hX", &bs_in[0], &bs_in[1], &bs_in[2], &bs_in[3], &bs_in[4], &bs_in[5]) == 6) { longmac |= (uint64_t) bs_in[0] << ((MAC_LEN - 0 - 1) * 8); longmac |= (uint64_t) bs_in[1] << ((MAC_LEN - 1 - 1) * 8); longmac |= (uint64_t) bs_in[2] << ((MAC_LEN - 2 - 1) * 8); longmac |= (uint64_t) bs_in[3] << ((MAC_LEN - 3 - 1) * 8); longmac |= (uint64_t) bs_in[4] << ((MAC_LEN - 4 - 1) * 8); longmac |= (uint64_t) bs_in[5] << ((MAC_LEN - 5 - 1) * 8); // If it has a mask component, get that const char *in_mask = strchr(in, '/'); if (in_mask != NULL) { longmask = 0; // See if it's numerical or expanded if (strchr(in_mask + 1, ':') != NULL) { // expanded, sscanf hex octets if (sscanf(in_mask + 1, "%hX:%hX:%hX:%hX:%hX:%hX", &bs_in[0], &bs_in[1], &bs_in[2], &bs_in[3], &bs_in[4], &bs_in[5]) == 6) { longmask |= (uint64_t) bs_in[0] << ((MAC_LEN - 0 - 1) * 8); longmask |= (uint64_t) bs_in[1] << ((MAC_LEN - 1 - 1) * 8); longmask |= (uint64_t) bs_in[2] << ((MAC_LEN - 2 - 1) * 8); longmask |= (uint64_t) bs_in[3] << ((MAC_LEN - 3 - 1) * 8); longmask |= (uint64_t) bs_in[4] << ((MAC_LEN - 4 - 1) * 8); longmask |= (uint64_t) bs_in[5] << ((MAC_LEN - 5 - 1) * 8); } else { error = 1; } } else { // numerical, scan and shift int nummask; if (sscanf(in_mask + 1, "%d", &nummask) == 1) { if (nummask == 48) nummask = 0; longmask = ((uint64_t) -1 << (48 - nummask)); } else { error = 1; } } } } else { error = 1; } delete[] bs_in; } inline mac_addr() { longmac = 0; longmask = (uint64_t) -1; error = 0; } inline mac_addr(const uint8_t *in) { longmac = 0; longmask = (uint64_t) -1; error = 0; longmac |= (uint64_t) in[0] << ((MAC_LEN - 0 - 1) * 8); longmac |= (uint64_t) in[1] << ((MAC_LEN - 1 - 1) * 8); longmac |= (uint64_t) in[2] << ((MAC_LEN - 2 - 1) * 8); longmac |= (uint64_t) in[3] << ((MAC_LEN - 3 - 1) * 8); longmac |= (uint64_t) in[4] << ((MAC_LEN - 4 - 1) * 8); longmac |= (uint64_t) in[5] << ((MAC_LEN - 5 - 1) * 8); } inline mac_addr(const uint8_t *in, const uint8_t *maskin) { longmac = 0; longmask = 0; error = 0; longmac |= (uint64_t) in[0] << ((MAC_LEN - 0 - 1) * 8); longmac |= (uint64_t) in[1] << ((MAC_LEN - 1 - 1) * 8); longmac |= (uint64_t) in[2] << ((MAC_LEN - 2 - 1) * 8); longmac |= (uint64_t) in[3] << ((MAC_LEN - 3 - 1) * 8); longmac |= (uint64_t) in[4] << ((MAC_LEN - 4 - 1) * 8); longmac |= (uint64_t) in[5] << ((MAC_LEN - 5 - 1) * 8); longmask |= (uint64_t) maskin[0] << ((MAC_LEN - 0 - 1) * 8); longmask |= (uint64_t) maskin[1] << ((MAC_LEN - 1 - 1) * 8); longmask |= (uint64_t) maskin[2] << ((MAC_LEN - 2 - 1) * 8); longmask |= (uint64_t) maskin[3] << ((MAC_LEN - 3 - 1) * 8); longmask |= (uint64_t) maskin[4] << ((MAC_LEN - 4 - 1) * 8); longmask |= (uint64_t) maskin[5] << ((MAC_LEN - 5 - 1) * 8); } inline mac_addr(const unsigned short int *in) { longmac = 0; longmask = (uint64_t) -1; error = 0; longmac |= (uint64_t) in[0] << ((MAC_LEN - 0 - 1) * 8); longmac |= (uint64_t) in[1] << ((MAC_LEN - 1 - 1) * 8); longmac |= (uint64_t) in[2] << ((MAC_LEN - 2 - 1) * 8); longmac |= (uint64_t) in[3] << ((MAC_LEN - 3 - 1) * 8); longmac |= (uint64_t) in[4] << ((MAC_LEN - 4 - 1) * 8); longmac |= (uint64_t) in[5] << ((MAC_LEN - 5 - 1) * 8); } inline mac_addr(const char *in) { string2long(in); } inline mac_addr(const string in) { string2long(in.c_str()); } inline mac_addr(const string in, uint8_t in_phy) { string2long(in.c_str()); SetPhy(in_phy); } inline mac_addr(int in) { in = in; // Silence gcc longmac = 0; longmask = 0; error = 0; } // Masked MAC compare inline bool operator== (const mac_addr& op) const { if (longmask < op.longmask) return ((longmac & longmask) == (op.longmac & longmask)); return ((longmac & op.longmask) == (op.longmac & op.longmask)); } // MAC compare inline bool operator!= (const mac_addr& op) const { if (longmask < op.longmask) return ((longmac & longmask) != (op.longmac & longmask)); return ((longmac & op.longmask) != (op.longmac & op.longmask)); } // mac less-than-eq inline bool operator<=(const mac_addr& op) const { return (longmac & op.longmask) == (op.longmac & op.longmask); } // MAC less-than for STL sorts... inline bool operator< (const mac_addr& op) const { return ((longmac & longmask) < (op.longmac & longmask)); } mac_addr& operator= (const mac_addr& op) { longmac = op.longmac; longmask = op.longmask; error = op.error; return *this; } mac_addr& operator= (const char *in) { string2long(in); return *this; } mac_addr& operator++() { longmac++; return *this; } mac_addr operator++(int) { mac_addr tmp = *this; ++*this; return tmp; } inline uint8_t index64(uint64_t val, int index) const { // Bitshift kung-foo return (uint8_t) (val >> ((MAC_LEN - index - 1) * 8)); } inline const uint8_t operator[] (int index) const { int mdex = index; if (index < 0 || index >= MAC_LEN) mdex = 0; return index64(longmac, mdex); } inline void SetPhy(uint8_t in_phy) { longmac |= (uint64_t) in_phy << (6 * 8); // Force enable checking of the phy once one is set longmask |= (uint64_t) 0xFF << (6 * 6); } inline uint8_t GetPhy() { return index64(longmac, 5); } inline uint32_t OUI() const { return (longmac >> 24); } inline string Mac2String() const { char tempstr[MAC_STR_LEN]; snprintf(tempstr, MAC_STR_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", index64(longmac, 0), index64(longmac, 1), index64(longmac, 2), index64(longmac, 3), index64(longmac, 4), index64(longmac, 5)); return string(tempstr); } inline string MacMask2String() const { uint64_t maskedmac = longmac & longmask; char tempstr[(MAC_STR_LEN * 2) + 1]; snprintf(tempstr, (MAC_STR_LEN * 2) + 1, "%02X:%02X:%02X:%02X:%02X:%02X/%02X:%02X:%02X:%02X:%02X:%02X", index64(maskedmac, 0), index64(maskedmac, 1), index64(maskedmac, 2), index64(maskedmac, 3), index64(maskedmac, 4), index64(maskedmac, 5), index64(longmask, 0), index64(longmask, 1), index64(longmask, 2), index64(longmask, 3), index64(longmask, 4), index64(longmask, 5)); return tempstr; } }; // A templated container for storing groups of masked mac addresses. A stl-map // will work for single macs, but we need this for smart mask matching on // more complex sets. Iterators in this class only work as incremental, // because thats all I need right now. This whole thing is really an ugly, // ugly kluge, and if I really had any need for it to be more extendible I'd // rewrite it to use std::iterator and other good stuff. But, I don't, // it works, and I need to move on to other areas. template<class T> class macmap { protected: struct mask_vec_content { mac_addr mac; T value; }; struct mask_vec_offsets { unsigned int first; unsigned int last; }; class SortMaskVec { public: inline bool operator() (const macmap::mask_vec_content x, const macmap::mask_vec_content y) const { return (x.mac < y.mac); } }; public: // This isn't quite like STL iterators, because I'm too damned lazy to deal // with all the nasty STL hoop-jumping. This does provide a somewhat-stl-ish // interface to iterating through the singleton and masked maps class iterator { friend class macmap; public: inline iterator(macmap<T> *in_owner) { owner = in_owner; if (owner->singleton_map.size() > 0) { singleton_itr = owner->singleton_map.begin(); vector_itr = -1; first = singleton_itr->first; second = &(singleton_itr->second); } else if (owner->mask_vec.size() > 0) { singleton_itr = owner->singleton_map.end(); vector_itr = 0; first = owner->mask_vec[0].mac; second = &(owner->mask_vec[0].value); } else { singleton_itr = owner->singleton_map.end(); vector_itr = owner->mask_vec.size(); second = NULL; } } // Prefix inline iterator& operator++() { if (singleton_itr == owner->singleton_map.end()) { if ((++vector_itr) < (int) owner->mask_vec.size()) { first = owner->mask_vec[vector_itr].mac; second = &(owner->mask_vec[vector_itr].value); } } else if (++singleton_itr == owner->singleton_map.end()) { if ((++vector_itr) < (int) owner->mask_vec.size()) { first = owner->mask_vec[vector_itr].mac; second = &(owner->mask_vec[vector_itr].value); } } else { first = singleton_itr->first; second = &(singleton_itr->second); } return *this; } // Postfix inline iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } // equal inline bool operator==(const iterator& op) { return (singleton_itr == op.singleton_itr) && (vector_itr == op.vector_itr); } // not inline bool operator!=(const iterator& op) { return (singleton_itr != op.singleton_itr) || (vector_itr != op.vector_itr); } // pointer fake inline iterator *operator->() { return this; } mac_addr first; T *second; protected: inline void assign(typename map<mac_addr, T>::iterator in_itr) { singleton_itr = in_itr; vector_itr = -1; if (in_itr != owner->singleton_map.end()) { first = singleton_itr->first; second = &(singleton_itr->second); } } inline void assign(int in_itr) { singleton_itr = owner->singleton_map.end(); vector_itr = in_itr; if (in_itr < (int) owner->mask_vec.size()) { first = owner->mask_vec[vector_itr].mac; second = &(owner->mask_vec[vector_itr].value); } } typename map<mac_addr, T>::iterator singleton_itr; int vector_itr; macmap<T> *owner; }; friend class macmap<T>::iterator; inline iterator begin() { iterator ret(this); return ret; } inline iterator end() { iterator ret(this); ret.singleton_itr = singleton_map.end(); ret.vector_itr = mask_vec.size(); return ret; } // The caller will rebuild the index before using us... inline void fast_insert(mac_addr in_mac, T in_data) { // Single macs go into the singleton map if (in_mac.longmask == (uint64_t) -1) { singleton_map[in_mac] = in_data; return; } // Put them into the vector mask_vec_content content; content.mac = in_mac; content.value = in_data; mask_vec.push_back(content); } // This is a very expensive insert but it builds a system that allows // for fast searching, which is where we REALLY need the speed. inline void insert(mac_addr in_mac, T in_data) { // Single macs go into the singleton map if (in_mac.longmask == (uint64_t) -1) { singleton_map[in_mac] = in_data; return; } // Put them into the vector mask_vec_content content; content.mac = in_mac; content.value = in_data; mask_vec.push_back(content); reindex(); } // Do a relatively fast find... inline iterator find(mac_addr in_mac) { iterator ret(this); if (in_mac.longmask == (uint64_t) -1) { // Look in the singleton map... This is very fast. typename map<mac_addr, T>::iterator sitr = singleton_map.find(in_mac); if (sitr != singleton_map.end()) { ret.assign(sitr); return ret; } } if (vec_offset_map.find(in_mac) != vec_offset_map.end()) { // We matched a large key in the vector map. The vector is sorted // in decreasing granularity, so the first one we match we can count // as good and get out of here mask_vec_offsets oft = vec_offset_map[in_mac]; for (unsigned int x = oft.last; x >= oft.first; x--) { if (in_mac <= mask_vec[x].mac) { ret.assign(x); return ret; } } } return end(); } inline void erase(mac_addr in_mac) { iterator itr = find(in_mac); if (itr == end()) return; if (itr.singleton_itr != singleton_map.end()) { singleton_map.erase(itr.singleton_itr); reindex(); return; } if (itr.vector_itr >= 0 && itr.vector_itr < (int) mask_vec.size()) { mask_vec.erase(mask_vec.begin() + itr.vector_itr); reindex(); return; } } inline T& operator[](mac_addr& index) { iterator foo = find(index); // This isn't very clean but its better than heap corruption // and other horrible stuff if (foo == end()) { fprintf(stderr, "Something tried to use macmap[] to reference an " "element that doesn't exist. Fix me.\n"); exit(1); } return *(foo->second); } int size() { return singleton_map.size() + mask_vec.size(); } inline void clear(void) { vec_offset_map.clear(); singleton_map.clear(); mask_vec.clear(); } inline void reindex(void) { // Order it if (mask_vec.size() == 0) return; stable_sort(mask_vec.begin(), mask_vec.end(), SortMaskVec()); // Clear our old map of content vec_offset_map.clear(); // Split it into offset groups mask_vec_offsets ofst; ofst.last = mask_vec.size() - 1; ofst.first = mask_vec.size() - 1; mac_addr owner = mask_vec[ofst.last].mac; for (unsigned int x = 0; x < mask_vec.size(); x++) { // Masked compare... is it still a subset of us? if (owner != mask_vec[x].mac) { vec_offset_map[owner] = ofst; ofst.first = x; ofst.last = x; owner = mask_vec[x].mac; } else { ofst.last = x; } } // Clean up the last stuff vec_offset_map[owner] = ofst; vec_offset_map[owner] = ofst; } protected: map<mac_addr, T> singleton_map; vector<mask_vec_content> mask_vec; map<mac_addr, mask_vec_offsets> vec_offset_map; }; #endif ���������������kismet-2013-03-R1b/packetsource_ipwlive.cc����������������������������������������������������������0000664�0001750�0001750�00000013627�12124602454�020222� 0����������������������������������������������������������������������������������������������������ustar �dragorn�������������������������dragorn����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* This file is part of Kismet Kismet 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 2 of the License, or (at your option) any later version. Kismet 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. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/socket.h> #ifdef HAVE_LINUX_WIRELESS // Some kernels include ethtool headers in wireless.h and seem to break // terribly if these aren't defined typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long u64; #include <asm/types.h> #include <linux/if.h> #include <linux/wireless.h> #endif #include "util.h" #include "packetsourcetracker.h" #include "packetsource_ipwlive.h" #if (defined(HAVE_LIBPCAP) && defined(SYS_LINUX) && defined(HAVE_LINUX_WIRELESS)) int PacketSource_Ipwlive::AutotypeProbe(string in_device) { return 0; } int PacketSource_Ipwlive::RegisterSources(Packetsourcetracker *tracker) { tracker->RegisterPacketProto("ipwlivetap", this, "na", 0); return 1; } int PacketSource_Ipwlive::EnableMonitor() { char errstr[STATUS_MAX]; #if 0 // Pull the hardware address from the device and use it to re-seed // the UUID uint8_t hwnode[6]; if (Ifconfig_Get_Hwaddr(interface.c_str(), errstr, hwnode) < 0) { _MSG(errstr, MSGFLAG_ERROR); _MSG("Failed to fetch interface hardware flags for '" + interface + ", " "this will probably fully fail in a moment when we try to configure " "the interface, but we'll keep going.", MSGFLAG_ERROR); } src_uuid.GenerateTimeUUID(hwnode); #endif char dynif[32]; FILE *sysf; char path[1024]; int ifflags; if (Ifconfig_Get_Flags(interface.c_str(), errstr, &ifflags) < 0) { _MSG(errstr, MSGFLAG_ERROR); _MSG("Failed to get interface flags for livetap control interface", MSGFLAG_ERROR); return -1; } if ((ifflags & IFF_UP) == 0) { _MSG("The ipw control interface (" + interface + ") is not configured " "as 'up'. The ipwlivetap source reports traffic from a currently " "running interface. For pure rfmon, use ipwXXXX instead.", MSGFLAG_ERROR); return -1; } // Use the .../net/foo/device symlink into .../bus/pci/drivers snprintf(path, 1024, "/sys/class/net/%s/device/rtap_iface", interface.c_str()); // Open it in RO mode first and get the current state. I'm not sure how // well frewind works on proc virtual files so we'll close it and re-open // to set modes, instead of opening it in mixed rw if ((sysf = fopen(path, "r")) == NULL) { _MSG("Failed to open ipw sysfs rtap control file. Check that the " "version of the ipw drivers you are using is current enough to " "support livetap mode, and that your system has sysfs set up " "properly", MSGFLAG_ERROR); return -1; } if (fgets(dynif, 32, sysf) == NULL) { _MSG("Failed to read from the ipw rtap control file. Check that the " "version of the ipw drivers you are using is current enough to " "support livetap mode, and that your system has sysfs set up " "properly", MSGFLAG_ERROR); fclose(sysf); return -1; } // We're done with the ro fclose(sysf); // If it's -1 we aren't turned on, so we'll initialize if (strncmp(dynif, "-1", 32) == 0) { if ((sysf = fopen(path, "w")) == NULL) { _MSG("Failed to open the ipw rtap control file for writing " "(" + string(strerror(errno)) + "). Check that Kismet has " "the proper privilege levels (SUID or started as root) and " "that you are running a version of the ipw drivers current " "enough to support livetap mode.", MSGFLAG_ERROR); return -1; } fprintf(sysf, "1\n"); fclose(sysf); // Now open it AGAIN for reading to get the interface out of it if ((sysf = fopen(path, "r")) == NULL) { _MSG("Failed to open ipw sysfs rtap control file. Check that the " "version of the ipw drivers you are using is current enough to " "support livetap mode, and that your system has sysfs set up " "properly", MSGFLAG_ERROR); return -1; } if (fgets(dynif, 32, sysf) == NULL) { _MSG("Failed to read from the ipw rtap control file. Check that the " "version of the ipw drivers you are using is current enough to " "support livetap mode, and that your system has sysfs set up " "properly", MSGFLAG_ERROR); fclose(sysf); return -1; } // We're done with the ro fclose(sysf); // Wait for things to settle if interfaces are getting renamed sleep(1); } // Sanity check the interface we were told to use. A 0, 1, -1 probably // means a bad driver version or something if (strncmp(dynif, "-1", 32) == 0 || strncmp(dynif, "0", 32) == 0 || strncmp(dynif, "1", 32) == 0) { _MSG("Got a nonsense interface from the ipw rtap control file. This " "probably means there is something unexpected happening with the " "ipw drivers. Check your system messages (dmesg)", MSGFLAG_ERROR); return -1; } // Bring up the dynamic interface if (Ifconfig_Delta_Flags(dynif, errstr, (IFF_UP | IFF_RUNNING | IFF_PROMISC)) < 0) { _MSG(errstr, MSGFLAG_ERROR); _MSG("Unable to set ipw livetap dynamic interface to 'up'", MSGFLAG_ERROR); return -1; } interface = dynif; return 0; } int PacketSource_Ipwlive::DisableMonitor() { return PACKSOURCE_UNMONITOR_RET_SILENCE; } int PacketSource_Ipwlive::SetChannel(unsigned int in_ch) { return 1; } int PacketSource_Ipwlive::FetchChannel() { return 0; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������