diff options
-rw-r--r-- | CMakeLists.txt | 10 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | include/wifi-triangulator/core.h | 27 | ||||
-rw-r--r-- | src/capture.cpp | 45 | ||||
-rw-r--r-- | src/core.cpp | 133 | ||||
-rw-r--r-- | src/formatter.cpp | 50 | ||||
-rw-r--r-- | src/misc.cpp | 28 | ||||
-rw-r--r-- | src/receiver.cpp | 29 | ||||
-rw-r--r-- | src/transmitter.cpp | 28 | ||||
-rw-r--r-- | wifi-triangulator.proto | 24 |
10 files changed, 259 insertions, 130 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 141beda..df5472a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,15 @@ if (NOT HAVE_PCAP_H) endif () find_package(Protobuf REQUIRED) -include_directories(${Protobuf_INCLUDE_DIRS} ${Protobuf_INCLUDE_DIR}) + +check_include_files("iwlib.h" HAVE_IWLIB_H) + +if (NOT HAVE_IWLIB_H) + message(FATAL_ERROR "Missing iwlib.h. You should probably install libiw-dev.") +endif () # lib wifi-triangulator +include_directories(${Protobuf_INCLUDE_DIRS} ${Protobuf_INCLUDE_DIR}) protobuf_generate_cpp(PROTO_SRC PROTO_HEADER wifi-triangulator.proto) add_library(wifi-triangulator @@ -35,7 +41,7 @@ target_link_libraries(wifi-triangulator PUBLIC pcap ${Protobuf_LIBRARIES}) # capture add_executable(capture src/capture.cpp) -target_link_libraries(capture PUBLIC wifi-triangulator) +target_link_libraries(capture PUBLIC wifi-triangulator iw) # transmitter add_executable(transmitter src/transmitter.cpp) @@ -7,6 +7,15 @@ # Running - sudo ifconfig wlan0 down - sudo iwconfig wlan0 mode monitor - sudo build/wifi-triangulator wlan0 +Set all available wlan interfaces in monitor mode on different channels: + + /sbin/iw dev | sed -n 's,.*Interface \(.*\),\1,p' |sort -n | while read iface; do + echo "Configuring $iface" + sudo ifconfig $iface down + n=$(echo $iface | sed 's,wlan\(.*\),\1,') + sudo ifconfig $iface channel $(($n+1)) + sudo iwconfig $iface mode monitor + sudo ifconfig $iface up + done + + sudo build/capture wlan0 | build/transmitter 10.13.37.30 diff --git a/include/wifi-triangulator/core.h b/include/wifi-triangulator/core.h index 042490a..15fb07b 100644 --- a/include/wifi-triangulator/core.h +++ b/include/wifi-triangulator/core.h @@ -9,6 +9,10 @@ namespace wifi_triangulator { +extern std::string app_name; + +typedef std::basic_string<uint8_t> bstring; + struct eth_mac { uint8_t a, b, c, d, e, f; @@ -45,21 +49,36 @@ struct eth_mac { class data { public: - pb::packet_type type; + pb::frame_type type; long sec; long usec; int rssi; + int mhz; eth_mac src, dst; - data(pb::packet_type type, long sec, long usec, int rssi, eth_mac src, eth_mac dst) : - type(type), sec(sec), usec(usec), src(src), rssi(rssi), dst(dst) {} + data(pb::frame_type type, long sec, long usec, int rssi, int mhz, eth_mac src, eth_mac dst) : + type(type), sec(sec), usec(usec), rssi(rssi), mhz(mhz), src(src), dst(dst) {} }; int launch_capture(std::string dev, std::function<void(const class data &)>); +int launch_reader(std::function<bool(uint16_t size, const uint8_t *data)> on_buffer); + +int launch_reader_envelope(std::function<bool(const pb::envelope &)> on_envelope); + +ssize_t read_stdin(uint8_t *data, size_t left); + +//void write_stdout(const bstring &s); + +void write_stdout(const std::string &s); + +void write_stdout(const uint8_t *data, size_t count); + +void write_envelope(pb::letter_type lt, pb::envelope &envelope); + } // namespace wifi_triangulator namespace std { -string to_string(wifi_triangulator::pb::packet_type t); +string to_string(wifi_triangulator::pb::frame_type t); } // namespace std diff --git a/src/capture.cpp b/src/capture.cpp index 5844b25..a6cc713 100644 --- a/src/capture.cpp +++ b/src/capture.cpp @@ -1,10 +1,20 @@ #include <iostream> +#include <iwlib.h> #include "wifi-triangulator/core.h" using namespace std; using namespace wifi_triangulator; +void send_info(uint64_t freq) { + pb::envelope envelope; + pb::listener_station_info *i = envelope.mutable_listener_station_info(); + i->set_freq(freq); + write_envelope(pb::letter_type::listener_station_info_lt, envelope); +} + int main(int argc, char *argv[]) { + app_name = argv[0]; + if (argc != 2) { fprintf(stderr, "usage: %s [interface]\n", argv[0]); return EXIT_FAILURE; @@ -14,24 +24,39 @@ int main(int argc, char *argv[]) { GOOGLE_PROTOBUF_VERIFY_VERSION; - string str; - str.reserve(1 << 16); + int iw; + if ((iw = iw_sockets_open()) < 0) { + perror("Could not open iw sockets"); + return EXIT_FAILURE; + } + + wireless_config wc; + if (iw_get_basic_config(iw, dev.c_str(), &wc) < 0) { + perror("iw_get_basic_config"); + return EXIT_FAILURE; + } + + auto freq = static_cast<uint64_t>(wc.freq); + + send_info(freq); int ret = launch_capture(dev, [&](const data &data) { pb::envelope envelope; envelope.set_time_s(data.sec); envelope.set_time_us(data.usec); - envelope.set_type(data.type); - if (data.type == pb::packet_type::probe_request) { - pb::probe *probe = envelope.mutable_probe(); + pb::frame *frame = envelope.mutable_frame(); + frame->set_type(data.type); + + if (data.type == pb::frame_type ::probe_request) { + pb::probe *probe = frame->mutable_probe(); probe->set_src(data.src); - probe->set_dst(static_cast<uint64_t>(data.dst)); - probe->set_rssi(data.rssi); + if (data.rssi) { + probe->set_rssi(data.rssi); + } } - envelope.SerializeToString(&str); - cout << static_cast<uint16_t>(str.length()) << str << flush; + write_envelope(pb::letter_type::frame_lt, envelope); // static int count = 0; // cerr << "count=" << count << "!\r" << flush; @@ -40,7 +65,7 @@ int main(int argc, char *argv[]) { google::protobuf::ShutdownProtobufLibrary(); - cerr << "Capture exiting" << endl; + cerr << app_name << " exiting" << endl; cout.flush(); return ret; diff --git a/src/core.cpp b/src/core.cpp index 8cb595f..69d38cf 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,4 +1,5 @@ -#include <stdlib.h> +#include <unistd.h> +#include <cstdlib> #include <iostream> #include <pcap.h> #include <cinttypes> @@ -7,11 +8,13 @@ #include "../third-party/radiotap-library/radiotap.h" #include "wifi-triangulator/core.h" -using std::string; +using namespace std; using namespace wifi_triangulator::pb; namespace wifi_triangulator { +std::string app_name; + struct ieee802_11_header { uint8_t frame_1; uint8_t frame_2; @@ -97,6 +100,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa auto *present_ptr = &rtaphdr->it_present; bool is_radiotap = true; + uint16_t mhz = 0; int rssi = 0; do { uint32_t present = *present_ptr; @@ -128,7 +132,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa present &= ~(1 << IEEE80211_RADIOTAP_RATE); } if (present & 1 << IEEE80211_RADIOTAP_CHANNEL) { - uint16_t mhz = it.read16u(); + mhz = it.read16u(); uint16_t bitmap = it.read16u(); snprintf(buf, 100, "IEEE80211_RADIOTAP_CHANNEL: %d MHz, flags=%04x\n", mhz, bitmap); @@ -181,7 +185,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa if (present & 1 << IEEE80211_RADIOTAP_ANTENNA) { uint8_t antenna = it.read8u(); - snprintf(buf, 100, "IEEE80211_RADIOTAP_ANTENNA: antenna=%d\n", antenna); +// snprintf(buf, 100, "IEEE80211_RADIOTAP_ANTENNA: antenna=%d\n", antenna); present &= ~(1 << IEEE80211_RADIOTAP_ANTENNA); } if (present & 1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) { @@ -199,7 +203,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa if (present & 1 << IEEE80211_RADIOTAP_RX_FLAGS) { uint16_t rx_flags = it.read16u(); - snprintf(buf, 100, "IEEE80211_RADIOTAP_RX_FLAGS: rx_flags=%d\n", rx_flags); +// snprintf(buf, 100, "IEEE80211_RADIOTAP_RX_FLAGS: rx_flags=%d\n", rx_flags); present &= ~(1 << IEEE80211_RADIOTAP_RX_FLAGS); } if (present & 1 << IEEE80211_RADIOTAP_TX_FLAGS) { @@ -214,7 +218,8 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa break; } -// printf(buf); +// fprintf(stderr, buf); +// fflush(stderr); /* int bit = 0; uint32_t mask = 1; @@ -235,43 +240,43 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa uint8_t type = ieee802_11_header->frame_1; - packet_type t; + frame_type t; switch (type) { case 0x40: - t = packet_type::probe_request; + t = frame_type::probe_request; break; case 0x80: - t = packet_type::beacon; + t = frame_type::beacon; break; case 0x50: - t = packet_type::probe_response; + t = frame_type::probe_response; break; case 0x48: - t = packet_type::null; + t = frame_type::null; break; case 0xd4: - t = packet_type::ack; + t = frame_type::ack; break; case 0x08: - t = packet_type::data; + t = frame_type::data; break; case 0xc4: - t = packet_type::cts; + t = frame_type::cts; break; case 0xb4: - t = packet_type::rts; + t = frame_type::rts; break; case 0x1e: - t = packet_type::cf_end; + t = frame_type::cf_end; break; case 0x1f: - t = packet_type::cf_end_cf_ack; + t = frame_type::cf_end_cf_ack; break; case 0x1a: - t = packet_type::ps_poll; + t = frame_type::ps_poll; break; default: - t = packet_type::unknown; + t = frame_type::unknown; } // printf("ieee802_11_header->frame_ctl=%02x, %s\n", type, type_str ? type_str : "???"); @@ -299,7 +304,8 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa ctx->data_consumer(data{ t, header->ts.tv_sec, header->ts.tv_usec, - rssi, src, dst}); + rssi, mhz, + src, dst}); } int launch_capture(string dev, std::function<void(const class data &)> data_consumer) { @@ -336,12 +342,10 @@ int launch_capture(string dev, std::function<void(const class data &)> data_cons auto ret = pcap_loop(handle, 1000, got_packet, reinterpret_cast<u_char *>(&ctx)); if (ret == -1) { - printf("pcap failed: %s\n", - pcap_geterr(handle) - ); + printf("pcap failed: %s\n", pcap_geterr(handle)); break; } else if (ret == -2) { -// someone called break loop + // someone called break loop break; } } @@ -351,4 +355,85 @@ int launch_capture(string dev, std::function<void(const class data &)> data_cons return EXIT_SUCCESS; } +int launch_reader(std::function<bool(uint16_t size, const uint8_t *data)> on_buffer) { + uint8_t buffer[1 << 16]; + while (true) { + uint16_t size; + + if (read_stdin(reinterpret_cast<uint8_t *>(&size), 2) < 0) { + break; + } + + ssize_t got; + if ((got = read_stdin(buffer, size)) != size) { + cout << "short read, got=" << got << endl; + return EXIT_FAILURE; + } + + bool ok = on_buffer(size, buffer); + + if (!ok) { + break; + } + } + + return EXIT_SUCCESS; +} + +int launch_reader_envelope(std::function<bool(const pb::envelope &)> on_envelope) { + pb::envelope envelope; + + return launch_reader([&](uint16_t size, const uint8_t *data) { + bool ok = envelope.ParseFromArray(data, size); + return ok && on_envelope(envelope); + }); +} + +ssize_t read_stdin(uint8_t *data, const size_t count) { + auto left = count; + while (left > 0) { + ssize_t n_read = read(STDIN_FILENO, data, left); + + if (n_read < 0) { + return n_read; + } + + left -= n_read; + } + + return count; +} + +//void write_stdout(const bstring &s) { +// write_stdout(s.c_str(), s.length()); +//} + +void write_stdout(const std::string &s) { + static_assert(sizeof(char) == sizeof(uint8_t), "bad sizes"); + write_stdout(reinterpret_cast<const uint8_t *>(s.c_str()), s.length()); +} + +void write_stdout(const uint8_t *data, size_t count) { + size_t left = count; + const uint8_t *buf = data; + while (left > 0) { + auto written = write(STDOUT_FILENO, data, left); + buf += written; + left -= written; + } + syncfs(STDOUT_FILENO); +} + +void write_envelope(pb::letter_type lt, pb::envelope &envelope) { + std::string str; + str.reserve(64 * 1024); + + envelope.set_type(lt); + + envelope.SerializeToString(&str); + uint16_t len = static_cast<uint16_t>(str.length()); + write_stdout(reinterpret_cast<uint8_t *>(&len), 2); + write_stdout(str); +} + } // namespace wifi_triangulator diff --git a/src/formatter.cpp b/src/formatter.cpp index b165a89..e4874dc 100644 --- a/src/formatter.cpp +++ b/src/formatter.cpp @@ -7,21 +7,42 @@ using namespace wifi_triangulator; void on_probe_request(const pb::probe &p) { cout << "PROBE REQUEST" << ", src=" << eth_mac(p.src()).to_string() - << ", dst=" << eth_mac(p.dst()).to_string() << ", rssi=" << p.rssi() << flush << endl; } -void on_envelope(pb::envelope envelope) { - if (envelope.type() == pb::probe_request) { - on_probe_request(envelope.probe()); +void on_frame(const pb::frame &f) { + if (f.type() == pb::frame_type::probe_request) { + on_probe_request(f.probe()); } else { - cout << to_string(envelope.type()) << endl; +// cout << "frame: " << to_string(f.type()) << endl; } } +void on_listener_station_info(const pb::listener_station_info &i) { + cout << "LISTENER STATION INFO" + << " mac=" << eth_mac(i.mac()).to_string() + << ", freq=" << i.freq() + << flush + << endl; +} + +bool on_envelope(const pb::envelope &envelope) { + if (envelope.type() == pb::letter_type::frame_lt) { + on_frame(envelope.frame()); + } else if (envelope.type() == pb::letter_type ::listener_station_info_lt) { + on_listener_station_info(envelope.listener_station_info()); + } else { + cout << "Unknown letter type: " << envelope.type() << endl; + } + + return true; +} + int main(int argc, char *argv[]) { + app_name = argv[0]; + GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 1) { @@ -29,24 +50,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - int count = 0; - uint8_t buffer[1 << 16]; - while (!feof(stdin)) { - pb::envelope envelope; - - uint16_t size; - cin >> size; - cin.read(reinterpret_cast<char *>(buffer), size); - bool ok = envelope.ParseFromArray(buffer, size); - if (!ok) { - cerr << "bad read" << endl; - continue; - } - -// cerr << "count=" << count++ << endl; - - on_envelope(envelope); - } + launch_reader_envelope(on_envelope); google::protobuf::ShutdownProtobufLibrary(); diff --git a/src/misc.cpp b/src/misc.cpp index ffe174f..cd45013 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,33 +1,33 @@ #include "wifi-triangulator/core.h" namespace std { -string to_string(wifi_triangulator::pb::packet_type t) { - using wifi_triangulator::pb::packet_type; +string to_string(wifi_triangulator::pb::frame_type t) { + using wifi_triangulator::pb::frame_type; switch (t) { - case packet_type::probe_request: + case frame_type::probe_request: return "probe request"; - case packet_type::beacon: + case frame_type::beacon: return "beacon"; - case packet_type::probe_response: + case frame_type::probe_response: return "probe response"; - case packet_type::null: + case frame_type::null: return "null"; - case packet_type::ack: + case frame_type::ack: return "ack"; - case packet_type::data: + case frame_type::data: return "data"; - case packet_type::cts: + case frame_type::cts: return "cts"; - case packet_type::rts: + case frame_type::rts: return "rts"; - case packet_type::cf_end: + case frame_type::cf_end: return "cf-end"; - case packet_type::cf_end_cf_ack: + case frame_type::cf_end_cf_ack: return "cf-end+cf-ack"; - case packet_type::ps_poll: + case frame_type::ps_poll: return "ps-poll"; - case packet_type::unknown: + case frame_type::unknown: default: return "unknown"; } diff --git a/src/receiver.cpp b/src/receiver.cpp index c6c5bdc..7ac940a 100644 --- a/src/receiver.cpp +++ b/src/receiver.cpp @@ -9,15 +9,9 @@ using namespace std; using namespace wifi_triangulator; -void on_probe_request(const pb::probe &p) { - cerr << "PROBE REQUEST" - << ", src=" << eth_mac(p.src()).to_string() - << ", dst=" << eth_mac(p.dst()).to_string() - << ", rssi=" << p.rssi() - << endl; -} - int main(int argc, char *argv[]) { + app_name = argv[0]; + if (argc != 1) { fprintf(stderr, "usage: %s\n", argv[0]); return EXIT_FAILURE; @@ -48,23 +42,12 @@ int main(int argc, char *argv[]) { struct sockaddr_in si_other; socklen_t addr_len; if ((n_read = ::recvfrom(s, bytes, len, 0, reinterpret_cast<struct sockaddr *>(&si_other), &addr_len)) == -1) { - throw std::runtime_error("recvfrom"); + throw std::runtime_error("recvfrom: " + string(strerror(errno))); } - string str; - for (socklen_t i = 0; i < n_read; i++) { - str += bytes[i]; - } - - istringstream ss{str}; - bool ok = envelope.ParseFromIstream(&ss); - if (ok) { - if (envelope.type() == pb::probe_request) { - on_probe_request(envelope.probe()); - } - } else { - cerr << "FAIL n_read=" << n_read << flush << endl; - } + uint16_t size = static_cast<uint16_t>(n_read); + write_stdout(reinterpret_cast<uint8_t *>(&size), 2); + write_stdout(bytes, static_cast<size_t>(n_read)); } google::protobuf::ShutdownProtobufLibrary(); diff --git a/src/transmitter.cpp b/src/transmitter.cpp index 047d37d..42295bb 100644 --- a/src/transmitter.cpp +++ b/src/transmitter.cpp @@ -46,32 +46,14 @@ int main(int argc, char *argv[]) { addr = reinterpret_cast<struct sockaddr *>(&addr_si); addr_len = sizeof(addr_si); - int count = 0; - uint8_t buffer[1 << 16]; - while (!feof(stdin)) { - pb::envelope envelope; - - uint16_t size; - - cin >> size; - cin.read(reinterpret_cast<char *>(buffer), size); - - /* - bool ok = envelope.ParseFromArray(buffer, size); - if (!ok) { - cerr << "bad read" << endl; - continue; - } - */ - - if (sendto(s, buffer, size, 0, addr, addr_len) == -1) { + launch_reader([&](uint16_t size, const uint8_t* data) { + if (sendto(s, data, size, 0, addr, addr_len) == -1) { throw std::runtime_error("sendto failed"); } - cerr << "count=" << count++ << endl; - } - - cerr << "transmitter exiting" << endl; + return true; + }); + cerr << app_name << " exiting" << endl; google::protobuf::ShutdownProtobufLibrary(); diff --git a/wifi-triangulator.proto b/wifi-triangulator.proto index 959a370..accd829 100644 --- a/wifi-triangulator.proto +++ b/wifi-triangulator.proto @@ -2,7 +2,12 @@ syntax = "proto3"; package wifi_triangulator.pb; -enum packet_type { +message listener_station_info { + fixed64 mac = 1; + int64 freq = 2; +} + +enum frame_type { unknown = 0; probe_request = 1; beacon = 2; @@ -20,13 +25,24 @@ enum packet_type { message probe { sint32 rssi = 1; fixed64 src = 2; - fixed64 dst = 3; +} + +message frame { + frame_type type = 3; + probe probe = 20; +} + +enum letter_type { + unknown_lt = 0; + listener_station_info_lt = 1; + frame_lt = 2; } message envelope { sfixed64 time_s = 1; sfixed64 time_us = 2; - packet_type type = 3; - probe probe = 20; + letter_type type = 3; + listener_station_info listener_station_info = 20; + frame frame = 21; } |