aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt41
-rw-r--r--capture.cpp108
-rw-r--r--core.cpp (renamed from main.cpp)154
-rw-r--r--include/wifi-triangulator/core.h65
-rw-r--r--misc.cpp35
-rw-r--r--receiver.cpp80
m---------third-party/radiotap-library0
-rw-r--r--wifi-triangulator.proto29
8 files changed, 417 insertions, 95 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba802f4..6fa065d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,21 +1,42 @@
cmake_minimum_required(VERSION 3.6)
+project(wifi-triangulator)
+
include(CheckIncludeFiles)
include(CheckLibraryExists)
-project(wifi-triangulator)
+include(FindProtobuf)
set(CMAKE_CXX_STANDARD 14)
+######################################################
+# Check dependencies
check_include_files("pcap.h" HAVE_PCAP_H)
-if(NOT HAVE_PCAP_H)
+if (NOT HAVE_PCAP_H)
message(FATAL_ERROR "Missing pcap.h. You should probably install libpcap-dev or similar.")
-endif()
+endif ()
+
+find_package(Protobuf REQUIRED)
+include_directories(${Protobuf_INCLUDE_DIRS} ${Protobuf_INCLUDE_DIR})
+
+# lib wifi-triangulator
+protobuf_generate_cpp(PROTO_SRC PROTO_HEADER wifi-triangulator.proto)
+
+add_library(wifi-triangulator
+ core.cpp misc.cpp
+ ${PROTO_SRC}
+ ${PROTO_HEADER}
+ include/wifi-triangulator/core.h
+ third-party/radiotap-library/radiotap.c
+ third-party/radiotap-library/radiotap.h
+ third-party/radiotap-library/radiotap_iter.h
+ third-party/radiotap-library/platform.h)
+target_include_directories(wifi-triangulator PUBLIC include ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(wifi-triangulator PUBLIC pcap ${Protobuf_LIBRARIES})
-set(SOURCE_FILES main.cpp
- third-party/radiotap-library/radiotap.c
- third-party/radiotap-library/radiotap.h
- third-party/radiotap-library/radiotap_iter.h
- third-party/radiotap-library/platform.h)
-add_executable(wifi-triangulator ${SOURCE_FILES})
+# capture
+add_executable(capture capture.cpp)
+target_link_libraries(capture PUBLIC wifi-triangulator)
-target_link_libraries(wifi-triangulator PUBLIC pcap)
+# receiver
+add_executable(receiver receiver.cpp)
+target_link_libraries(receiver PUBLIC wifi-triangulator)
diff --git a/capture.cpp b/capture.cpp
new file mode 100644
index 0000000..7e51fcd
--- /dev/null
+++ b/capture.cpp
@@ -0,0 +1,108 @@
+#include <iostream>
+#include "wifi-triangulator/core.h"
+#include "wifi-triangulator.pb.h"
+
+#include <sstream>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <exception>
+#include <cstring>
+
+using namespace std;
+using namespace wifi_triangulator;
+
+class output {
+public:
+ virtual void handle(const data &) = 0;
+};
+
+class human_output : public output {
+public:
+ void handle(const data &data) {
+ printf("timestamp=%lu, rssi=%d, src=%s, dst=%s, type=%s\n", ((data.sec * 1000 * 1000) + data.usec) * 1000,
+ data.rssi, data.src.to_string().c_str(), data.dst.to_string().c_str(), to_string(data.type).c_str());
+ fflush(stdout);
+ };
+};
+
+class protobuf_output : public output {
+ int s;
+ struct sockaddr_in addr_si;
+ struct sockaddr *addr;
+ socklen_t addr_len;
+
+public:
+ protobuf_output(string host, uint16_t port) {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ throw std::runtime_error("socket");
+
+
+ memset((char *) &addr_si, 0, sizeof(addr_si));
+ addr_si.sin_family = AF_INET;
+ addr_si.sin_port = htons(port);
+ if (inet_aton(host.c_str(), &addr_si.sin_addr) == 0) {
+ throw std::runtime_error("inet_aton() failed");
+ }
+
+ addr = reinterpret_cast<struct sockaddr *>(&addr_si);
+ addr_len = sizeof(addr_si);
+ }
+
+ ~protobuf_output() {
+ google::protobuf::ShutdownProtobufLibrary();
+ }
+
+ void handle(const data &data) override {
+ pb::envelope envelope;
+ envelope.set_type(data.type);
+
+ if (data.type == pb::packet_type::probe_request) {
+ pb::probe *probe = envelope.mutable_probe();
+ probe->set_src(data.src);
+ probe->set_dst(static_cast<uint64_t>(data.dst));
+ probe->set_rssi(data.rssi);
+ }
+
+ std::string str;
+ envelope.SerializeToString(&str);
+
+ if (sendto(s, str.c_str(), str.length(), 0, addr, addr_len) == -1) {
+ throw std::runtime_error("sendto failed");
+ }
+ cout << flush;
+
+ static int count = 0;
+ cerr << "count=" << count << ", len=" << str.length() << "!\r" << flush;
+ count++;
+ }
+};
+
+bool human = false;
+
+int main(int argc, char *argv[]) {
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s [interface] [host]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ string dev = argv[1];
+ string host = argv[2];
+
+ output *output;
+ if (human) {
+ output = new human_output;
+ } else {
+ cerr << "Sending to stdout" << flush << endl;
+ output = new protobuf_output(host, 3333);
+ }
+
+ return launch_capture(dev, [&](const data &data) {
+ output->handle(data);
+ });
+}
diff --git a/main.cpp b/core.cpp
index 9f3028e..11a20f7 100644
--- a/main.cpp
+++ b/core.cpp
@@ -5,34 +5,12 @@
#include <sstream>
#include <iomanip>
#include "third-party/radiotap-library/radiotap.h"
+#include "wifi-triangulator/core.h"
-struct eth_mac {
- uint8_t a, b, c, d, e, f;
-
- const std::string to_string() {
- std::stringstream s;
- s << std::hex << std::setw(2) << std::setfill('0')
- << (int) a << ":"
- << std::setw(2) << std::setfill('0') << (int) b << ":"
- << std::setw(2) << std::setfill('0') << (int) c << ":"
- << std::setw(2) << std::setfill('0') << (int) d << ":"
- << std::setw(2) << std::setfill('0') << (int) e << ":"
- << std::setw(2) << std::setfill('0') << (int) f;
- return s.str();
- }
-};
-
-class data {
-public:
- time_t sec;
- suseconds_t usec;
+using std::string;
+using namespace wifi_triangulator::pb;
- int rssi;
- struct eth_mac src, dst;
-
- data() : sec(0), usec(0), src(), rssi(), dst() {
- }
-};
+namespace wifi_triangulator {
struct ieee802_11_header {
uint8_t frame_1;
@@ -93,14 +71,15 @@ struct radio_tap_it {
}
};
+struct capture_context {
+ std::function<void( const data &)> data_consumer;
+};
+
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
// fprintf(stdout, "%lu.%lu, caplen=%d, len=%d\n", header->ts.tv_sec, header->ts.tv_usec, header->caplen, header->len);
- struct ieee80211_radiotap_header *rtaphdr = (struct ieee80211_radiotap_header *) packet;
-
- class data data;
- data.sec = header->ts.tv_sec;
- data.usec = header->ts.tv_usec;
+ auto *ctx = reinterpret_cast<capture_context *>(args);
+ auto *rtaphdr = reinterpret_cast<const struct ieee80211_radiotap_header *>(packet);
if (rtaphdr->it_version != 0) {
return;
@@ -108,7 +87,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
int present_count = 0;
{
- uint32_t *present_ptr = &rtaphdr->it_present;
+ auto *present_ptr = &rtaphdr->it_present;
do {
present_count++;
} while ((*present_ptr++) & 1 << IEEE80211_RADIOTAP_EXT);
@@ -116,8 +95,9 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
radio_tap_it it(packet + 4 + 4 * present_count);
- uint32_t *present_ptr = &rtaphdr->it_present;
+ auto *present_ptr = &rtaphdr->it_present;
bool is_radiotap = true;
+ int rssi = 0;
do {
uint32_t present = *present_ptr;
bool next_is_radiotap = (present & 1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) != 0;
@@ -164,7 +144,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
if (present & 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) {
int8_t antsignal_dbm = it.read8s();
- data.rssi = antsignal_dbm;
+ rssi = antsignal_dbm;
snprintf(buf, 100, "IEEE80211_RADIOTAP_DBM_ANTSIGNAL: dbm=%d\n", antsignal_dbm);
present &= ~(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
}
@@ -255,126 +235,130 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
uint8_t type = ieee802_11_header->frame_1;
- std::string type_str;
+ packet_type t;
switch (type) {
case 0x40:
- type_str = "probe request";
+ t = packet_type::probe_request;
break;
case 0x80:
- type_str = "beacon";
+ t = packet_type::beacon;
break;
case 0x50:
- type_str = "probe response";
+ t = packet_type::probe_response;
break;
case 0x48:
- type_str = "null";
+ t = packet_type::null;
break;
case 0xd4:
- type_str = "ack";
+ t = packet_type::ack;
break;
case 0x08:
- type_str = "data";
+ t = packet_type::data;
break;
case 0xc4:
- type_str = "cts";
+ t = packet_type::cts;
break;
case 0xb4:
- type_str = "rts";
+ t = packet_type::rts;
break;
case 0x1e:
- type_str = "cf-end";
+ t = packet_type::cf_end;
break;
case 0x1f:
- type_str = "cf-end+cf-ack";
+ t = packet_type::cf_end_cf_ack;
break;
case 0x1a:
- type_str = "ps-poll";
+ t = packet_type::ps_poll;
break;
- default: {
- std::stringstream s;
- s << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int) type;
- type_str = s.str();
- }
+ default:
+ t = packet_type::unknown;
}
// printf("ieee802_11_header->frame_ctl=%02x, %s\n", type, type_str ? type_str : "???");
+ eth_mac src, dst;
+
if (!ieee802_11_header->is_from_ds()) {
if (!ieee802_11_header->is_to_ds()) {
- data.dst = ieee802_11_header->addr1;
- data.src = ieee802_11_header->addr2;
+ dst = ieee802_11_header->addr1;
+ src = ieee802_11_header->addr2;
} else {
- data.dst = ieee802_11_header->addr1;
- data.src = ieee802_11_header->addr3;
+ dst = ieee802_11_header->addr1;
+ src = ieee802_11_header->addr3;
}
} else {
if (!ieee802_11_header->is_to_ds()) {
- data.dst = ieee802_11_header->addr3;
- data.src = ieee802_11_header->addr2;
+ dst = ieee802_11_header->addr3;
+ src = ieee802_11_header->addr2;
} else {
- data.dst = ieee802_11_header->addr3;
- data.src = ieee802_11_header->addr4;
+ dst = ieee802_11_header->addr3;
+ src = ieee802_11_header->addr4;
}
}
- auto src = data.src.to_string();
- auto dst = data.dst.to_string();
- printf("timestamp=%lu, rssi=%d, src=%s, dst=%s, type=%s\n", ((data.sec * 1000 * 1000) + data.usec) * 1000,
- data.rssi, src.c_str(), dst.c_str(), type_str.c_str());
- /// printf("\036{\"timestamp_us\": %lu, \"rssi\": %d, \"src\": \"%s\", \"dst\": \"%s\"}\n", data.sec * 1000 * 1000 + data.usec, data.rssi, src.c_str(), dst.c_str());
-
- fflush(stdout);
+ ctx->data_consumer(data{
+ t,
+ header->ts.tv_sec, header->ts.tv_usec,
+ rssi, src, dst});
}
-int main(int argc, char *argv[]) {
+int launch_capture(string dev, std::function<void(const class data &)> data_consumer) {
char errbuf[1000];
- if (argc != 2) {
- fprintf(stderr, "usage: %s [interface]\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- char *dev = argv[1];
-
pcap_t *handle;
- handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
+ handle = pcap_open_live(dev.c_str(), BUFSIZ, 1, 1000, errbuf);
// handle = pcap_open_offline(dev, errbuf);
if (!handle) {
- fprintf(stderr, "Could not open %s: %s\n", dev, errbuf);
+ fprintf(stderr,
+ "Could not open %s: %s\n", dev.
+
+ c_str(), errbuf
+
+ );
return EXIT_FAILURE;
}
int i = pcap_datalink(handle);
if (i != DLT_IEEE802_11_RADIO) {
- fprintf(stderr, "Device %s doesn't provide IEEE 802.11 radio headers\n", dev);
- return (2);
+ fprintf(stderr,
+ "Device %s doesn't provide IEEE 802.11 radio headers\n", dev.
+
+ c_str()
+
+ );
+ return EXIT_FAILURE;
}
- /* Compile and apply the filter */
+/* Compile and apply the filter */
// if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
// fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
-// return(2);
+// return EXIT_FAILURE;
// }
// if (pcap_setfilter(handle, &fp) == -1) {
// fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
-// return(2);
+// return EXIT_FAILURE;
// }
+ capture_context ctx{data_consumer};
while (true) {
- auto ret = pcap_loop(handle, 1000, got_packet, nullptr);
+ 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;
}
}
pcap_close(handle);
- return (0);
+ return EXIT_SUCCESS;
}
+
+} // namespace wifi_triangulator
diff --git a/include/wifi-triangulator/core.h b/include/wifi-triangulator/core.h
new file mode 100644
index 0000000..042490a
--- /dev/null
+++ b/include/wifi-triangulator/core.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <cstdint>
+#include <sstream>
+#include <iomanip>
+#include <functional>
+
+#include "wifi-triangulator.pb.h"
+
+namespace wifi_triangulator {
+
+struct eth_mac {
+ uint8_t a, b, c, d, e, f;
+
+ eth_mac() {}
+
+ eth_mac(uint64_t value) : a(uint8_t(value >> 40 & 0xff)),
+ b(uint8_t(value >> 32 & 0xff)),
+ c(uint8_t(value >> 24 & 0xff)),
+ d(uint8_t(value >> 16 & 0xff)),
+ e(uint8_t(value >> 9 & 0xff)),
+ f(uint8_t(value & 0xff)) {}
+
+ std::string to_string() const {
+ std::stringstream s;
+ s << std::hex << std::setw(2) << std::setfill('0')
+ << (int) a << ":"
+ << std::setw(2) << std::setfill('0') << (int) b << ":"
+ << std::setw(2) << std::setfill('0') << (int) c << ":"
+ << std::setw(2) << std::setfill('0') << (int) d << ":"
+ << std::setw(2) << std::setfill('0') << (int) e << ":"
+ << std::setw(2) << std::setfill('0') << (int) f;
+ return s.str();
+ }
+
+ operator uint64_t() const {
+ return uint64_t(a) << 40 |
+ uint64_t(b) << 32 |
+ uint64_t(c) << 24 |
+ uint64_t(d) << 16 |
+ uint64_t(e) << 8 |
+ uint64_t(f);
+ }
+} __attribute__((packed));
+
+class data {
+public:
+ pb::packet_type type;
+ long sec;
+ long usec;
+
+ int rssi;
+ 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) {}
+};
+
+int launch_capture(std::string dev, std::function<void(const class data &)>);
+
+} // namespace wifi_triangulator
+
+namespace std {
+string to_string(wifi_triangulator::pb::packet_type t);
+} // namespace std
diff --git a/misc.cpp b/misc.cpp
new file mode 100644
index 0000000..ffe174f
--- /dev/null
+++ b/misc.cpp
@@ -0,0 +1,35 @@
+#include "wifi-triangulator/core.h"
+
+namespace std {
+string to_string(wifi_triangulator::pb::packet_type t) {
+ using wifi_triangulator::pb::packet_type;
+
+ switch (t) {
+ case packet_type::probe_request:
+ return "probe request";
+ case packet_type::beacon:
+ return "beacon";
+ case packet_type::probe_response:
+ return "probe response";
+ case packet_type::null:
+ return "null";
+ case packet_type::ack:
+ return "ack";
+ case packet_type::data:
+ return "data";
+ case packet_type::cts:
+ return "cts";
+ case packet_type::rts:
+ return "rts";
+ case packet_type::cf_end:
+ return "cf-end";
+ case packet_type::cf_end_cf_ack:
+ return "cf-end+cf-ack";
+ case packet_type::ps_poll:
+ return "ps-poll";
+ case packet_type::unknown:
+ default:
+ return "unknown";
+ }
+}
+} // namespace std
diff --git a/receiver.cpp b/receiver.cpp
new file mode 100644
index 0000000..c6c8f72
--- /dev/null
+++ b/receiver.cpp
@@ -0,0 +1,80 @@
+#include "wifi-triangulator/core.h"
+#include "wifi-triangulator.pb.h"
+
+#include <iostream>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <exception>
+#include <cstring>
+
+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[]) {
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ uint16_t port = 3333;
+ int s;
+ struct sockaddr_in si_me;
+ if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ throw std::runtime_error("socket");
+
+ memset((char *) &si_me, 0, sizeof(si_me));
+ si_me.sin_family = AF_INET;
+ si_me.sin_port = htons(port);
+ si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (::bind(s, reinterpret_cast<struct sockaddr *>(&si_me), sizeof(si_me)) == -1) {
+ throw std::runtime_error("bind");
+ }
+
+ sockaddr *me = reinterpret_cast<sockaddr *>(&si_me);
+
+ pb::envelope envelope;
+ while (true) {
+ size_t len = 64 * 1024;
+ uint8_t bytes[len];
+ ssize_t n_read;
+
+ 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");
+ }
+
+ 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;
+ }
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
diff --git a/third-party/radiotap-library b/third-party/radiotap-library
-Subproject 9fafde1c85e2705488b7fffdf6275b3889ec513
+Subproject b6fbcaf506080a96bfdda7b44309ad4a3d06556
diff --git a/wifi-triangulator.proto b/wifi-triangulator.proto
new file mode 100644
index 0000000..7daf9bf
--- /dev/null
+++ b/wifi-triangulator.proto
@@ -0,0 +1,29 @@
+syntax = "proto3";
+
+package wifi_triangulator.pb;
+
+enum packet_type {
+ unknown = 0;
+ probe_request = 1;
+ beacon = 2;
+ probe_response = 3;
+ null = 4;
+ ack = 5;
+ data = 6;
+ cts = 7;
+ rts = 8;
+ cf_end = 9;
+ cf_end_cf_ack = 10;
+ ps_poll = 11;
+};
+
+message probe {
+ sint32 rssi = 2;
+ fixed64 src = 3;
+ fixed64 dst = 4;
+}
+
+message envelope {
+ packet_type type = 1;
+ probe probe = 2;
+}