Compare commits

...

50 Commits

Author SHA1 Message Date
Ruakij 1c5a0638ed Calling packetHandler 3 years ago
Ruakij 69317e51f6 Changed arg to const ref 3 years ago
Ruakij 4f1cb82f46 Remove unused include 3 years ago
Ruakij b7b7f6edbb Fixed exception when signal-data could is missing 3 years ago
Ruakij 8d67321d4b Implemented payload-alanyzing (size) 3 years ago
Ruakij 61f3c432c9 Moved head-analyzing to own function 3 years ago
Ruakij 52119fe3cd Added handling of special packet-types with their respective data 3 years ago
Ruakij f938f8dd53 Finished packet-type detection 3 years ago
Ruakij 5b8a330e69 Added package-type 3 years ago
Ruakij 35e71ef44e Fixed default value 3 years ago
Ruakij 8ef6318a56 Added method to convert hex-char to hex-value 3 years ago
Ruakij 9301c4e0fd Added Copyconstrucotr for base and made inheritance public 3 years ago
Ruakij 4d8597b1d6 Made pass const 3 years ago
Ruakij 3c379a1a80 Rename split.hpp to string-helper.hpp 3 years ago
Ruakij 6710442067 Fixed missing imports 3 years ago
Ruakij e191085cbd Renamed ssid to lowercase 3 years ago
Ruakij f834ec7134 Fixed fields not being public 3 years ago
Ruakij 035491668a Fixed wrong key used 3 years ago
Ruakij 16028daf10 Auto-Remove newline-char 3 years ago
Ruakij 1ed9c84802 Added array to retrieve package-type names from enum 3 years ago
Ruakij a0ae919614 Removed asyncHandler and creating new threads now once buffer-vector is complete 3 years ago
Ruakij f1e8069afd Added specialisation-packets 3 years ago
Ruakij bbd9623256 Added helper for vector-stats 3 years ago
Ruakij 5ea6d1f975 Implemented usage of packetType-enum 3 years ago
Ruakij c87a95b167 Changed type to enum-packet-type 3 years ago
Ruakij ca1b59e4c6 Choose and set addresses to packet 3 years ago
Ruakij 5ecc7ed383 Added bssid to packet 3 years ago
Ruakij b10a0de9e6 Grabbing adresses if available from header 3 years ago
Ruakij 58a535401a Grabbing first data from header 3 years ago
Ruakij c37a214808 Added type-string 3 years ago
Ruakij 9ce2da6f61 Renamed size to payloadSize 3 years ago
Ruakij 177181668d Renamed linkSpeed to dataRate 3 years ago
Ruakij 9755e86a98 Change packet-macs to string 3 years ago
Ruakij c5bc468ab9 Added documentation to find 3 years ago
Ruakij ee3505090d Added helper-file for finding items in std::vector<std::string> 3 years ago
Ruakij cb33dd0f80 Moved timestampConvert to own helper-file 3 years ago
Ruakij 8a62d2899b Moved split to own helper-file 3 years ago
Ruakij 6de2063288 Implemented textTimestamp converter to timestampMicros 3 years ago
Ruakij 5d3e861fc9 Gathering first data from textPacket 3 years ago
Ruakij 9c18c50640 Added TextHandler to exec-call 3 years ago
Ruakij 8e5cb85c1a Fixed passing of handlerFunction-pointer 3 years ago
Ruakij e7dcaf99a0 Created empty PacketHandler 3 years ago
Ruakij 36f252437d Changed from only strings to vector-strings 3 years ago
Ruakij 5ac832623d Created empty TextPacketHandler 3 years ago
Ruakij 57b8ae868c Changed packet-timestamp to uint64_t for epoch-timestamp in micros 3 years ago
Ruakij e66f6c1140 Fixed strcopy being wrong way around 3 years ago
Ruakij f3b9eb25a7 Added missing pthread-library 3 years ago
Ruakij 35edc6ca6e Created basic chained handlers 3 years ago
Ruakij b8b2bb7202 Added basic packet-structure 3 years ago
Ruakij 3f7c92ba7e First implementation 3 years ago

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.0.0)
project(rfmon-to-influx VERSION 0.1.0)
include(CTest)
enable_testing()
add_executable(rfmon-to-influx main.cpp)
target_link_libraries(rfmon-to-influx pthread)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

@ -0,0 +1,18 @@
#ifndef FDDB997A_BCD3_4056_BFEA_9FF6A548DACF
#define FDDB997A_BCD3_4056_BFEA_9FF6A548DACF
#include "./packet.hpp"
#include <string>
class BeaconPacket : public Packet{
public:
BeaconPacket()
{}
BeaconPacket(const Packet &packet)
: Packet(packet)
{}
std::string ssid;
};
#endif /* FDDB997A_BCD3_4056_BFEA_9FF6A548DACF */

@ -0,0 +1,47 @@
#ifndef C42FA9F6_8CF3_453F_8FA0_918E543DCD59
#define C42FA9F6_8CF3_453F_8FA0_918E543DCD59
#include <string>
enum PacketType {
Beacon,
ProbeRequest,
ProbeResponse,
Data,
RequestToSend,
ClearToSend,
Acknowledgment,
BlockAcknowledgment,
NoData,
Unknown
};
const std::array<const char*, 10> PACKET_TYPE_NAMES({{
"Beacon",
"Probe Request",
"Probe Response",
"Data",
"Request to send",
"Clear to send",
"Acknowledgment",
"BlockAcknowledgment",
"NoData",
"Unknown"
}});
struct Packet {
uint64_t timestampMicros;
std::string srcMac;
std::string dstMac;
std::string bssid;
unsigned int payloadSize;
char signal;
unsigned int frequency;
unsigned char dataRate;
PacketType type;
};
#endif /* C42FA9F6_8CF3_453F_8FA0_918E543DCD59 */

@ -0,0 +1,18 @@
#ifndef CD2BF199_8153_4F10_A85C_50883FAD66A8
#define CD2BF199_8153_4F10_A85C_50883FAD66A8
#include "./packet.hpp"
#include <string>
class ProbeRequestPacket : public Packet{
public:
ProbeRequestPacket()
{}
ProbeRequestPacket(const Packet &packet)
: Packet(packet)
{}
std::string requestSsid;
};
#endif /* CD2BF199_8153_4F10_A85C_50883FAD66A8 */

@ -0,0 +1,18 @@
#ifndef B199B4B3_BE27_4F0C_8DBE_5E78580AB1A9
#define B199B4B3_BE27_4F0C_8DBE_5E78580AB1A9
#include "./packet.hpp"
#include <string>
class ProbeResponsePacket : public Packet{
public:
ProbeResponsePacket()
{}
ProbeResponsePacket(const Packet &packet)
: Packet(packet)
{}
std::string responseSsid;
};
#endif /* B199B4B3_BE27_4F0C_8DBE_5E78580AB1A9 */

@ -0,0 +1,28 @@
#ifndef C251BA62_6D80_4033_86B6_61F184E6F250
#define C251BA62_6D80_4033_86B6_61F184E6F250
#include <future>
#include <string>
#include "textPacketHandler.hpp"
using namespace std::string_literals;
std::vector<std::string> buffer;
void bufHandler(const char *buf){
std::string line = buf;
// Remove last char which is \n
line = line.substr(0, line.size()-1);
// When first char of buf has text (no tab), we got a new packet
if(buf[0] != '\t'){
// Submit the just-read text-packet in a new thread
if(buffer.size() != 0) {
(void)std::async(std::launch::async, textPacketHandler, buffer);
}
buffer = {line};
}
else
buffer.push_back(line); // Append part-packet
}
#endif /* C251BA62_6D80_4033_86B6_61F184E6F250 */

@ -0,0 +1,10 @@
#ifndef EA8E466A_DAAA_4747_9CEE_65B77A4EF694
#define EA8E466A_DAAA_4747_9CEE_65B77A4EF694
#include "../DTO/packet.hpp"
void packetHandler(const Packet &packet){
}
#endif /* EA8E466A_DAAA_4747_9CEE_65B77A4EF694 */

@ -0,0 +1,185 @@
#ifndef EE781A91_6D07_47AC_B3C4_F99E29F3731F
#define EE781A91_6D07_47AC_B3C4_F99E29F3731F
#include <string>
#include "../DTO/packet.hpp"
#include "../DTO/beaconPacket.hpp"
#include "../DTO/probeRequestPacket.hpp"
#include "../DTO/probeResponsePacket.hpp"
#include <vector>
#include <locale>
#include <iomanip>
#include "../helper/string-helper.hpp"
#include "../helper/timestampConvert.hpp"
#include "../helper/find.hpp"
#include "../helper/vector-stats.hpp"
#include <unordered_map>
#include "./packetHandler.hpp"
using namespace std::string_literals;
const std::unordered_map<std::string, PacketType> PACKET_TYPE_MAP({
{"Beacon", PacketType::Beacon},
{"Probe Request", PacketType::ProbeRequest},
{"Probe Response", PacketType::ProbeResponse},
{"Data", PacketType::Data},
{"Request-To-Send", PacketType::RequestToSend},
{"Clear-To-Send", PacketType::ClearToSend},
{"Acknowledgment", PacketType::Acknowledgment},
{"BA", PacketType::BlockAcknowledgment}
});
void parseHeader(Packet &packet, const std::vector<std::string> &textPacket);
void parsePayload(Packet &packet, const std::vector<std::string> &textPacket);
void textPacketHandler(const std::vector<std::string> textPacket){
/// Here we have to parse the packet
// Create empty packet
Packet packet;
parseHeader(packet, textPacket);
parsePayload(packet, textPacket);
packetHandler(packet);
}
void parseHeader(Packet &packet, const std::vector<std::string> &textPacket){
const std::string textHeader = textPacket[0];
const std::vector<std::string> headerData = split(textHeader, ' ');
std::string textTimestamp = headerData[0];
uint64_t timestamp = convertStringToTimestampMicros(textTimestamp);
// Find remaining data based on keys in/around fields
int linkSpeedIndex = findIs(headerData, "Mb/s", 1, 1);
packet.dataRate = std::stoi(headerData[linkSpeedIndex]);
int frequencyIndex = findIs(headerData, "MHz", 1, 1);
packet.frequency = std::stoi(headerData[frequencyIndex]);
int signalIndex = findIs(headerData, "signal", 1, 1);
if(signalIndex != -1){
std::string signalText = headerData[signalIndex].substr(0, 3);
packet.signal = std::stoi(signalText);
}
else {
fprintf(stderr, "Missing signal-data!\n");
packet.signal = -100;
}
// Addresses seem complicated at first, but just have many fields which might be available.
// SA and DA are src- and dst-Addresses
// BSSID is the used bssid
// TA and RA are transmitter- and receiver-address which are used exclusively for RTS and CTS in tcpdump
// BEWARE: SA, DA, BSSID, TA and RA can be used together, but tcpdump doesnt display all of them!
// DA might also not be a valid MAC-address, but Broadcast or an encoded IPv4/6 Multicast-address
int saIndex = findContains(headerData, "SA:", 1);
std::string sAddr = (saIndex != -1) ? headerData[saIndex].substr("SA:"s.length()) : "";
int daIndex = findContains(headerData, "DA:", 1);
std::string dAddr = (daIndex != -1) ? headerData[daIndex].substr("DA:"s.length()) : "";
int bssidIndex = findContains(headerData, "BSSID:", 1);
std::string bssidAddr = (bssidIndex != -1) ? headerData[bssidIndex].substr("BSSID:"s.length()) : "";
int taIndex = findContains(headerData, "TA:", 1);
std::string tAddr = (taIndex != -1) ? headerData[taIndex].substr("TA:"s.length()) : "";
int raIndex = findContains(headerData, "RA:", 1);
std::string rAddr = (raIndex != -1) ? headerData[raIndex].substr("RA:"s.length()) : "";
// Depending of when which address-fields are actually set, choose which ones to use
if(sAddr == "" && tAddr != "") sAddr = tAddr;
if(dAddr == "" && rAddr != "") dAddr = rAddr;
// Set addresses to packet
packet.srcMac = sAddr;
packet.dstMac = dAddr;
packet.bssid = bssidAddr;
// Identify type of packet
// -> comes right after the addresses
int typeIndex = max(std::vector({saIndex, daIndex, bssidIndex, taIndex, raIndex}))+1;
PacketType type = PacketType::Unknown;
if(typeIndex == headerData.size()) type = PacketType::NoData;
else {
std::string textType = headerData[typeIndex];
// Check for incomplete types
if(textType == "Probe"){
textType += " "+ headerData[typeIndex+1];
}
// If type is in map, use map-value, otherwise keep default
if(PACKET_TYPE_MAP.find(textType) != PACKET_TYPE_MAP.end())
type = PACKET_TYPE_MAP.at(textType);
if(type == PacketType::Unknown){
fprintf(stderr, "Unknown package-type: %s\n", textType.c_str());
}
}
packet.type = type;
// Read data for specializations
if(type == PacketType::Beacon){
// Create BeaconPacket from packet
BeaconPacket beaconPacket = BeaconPacket(packet);
packet = beaconPacket; // Overwrite packet
// Find ssid
int start = textHeader.find('(')+1;
std::string ssid = textHeader.substr(start, textHeader.find(')')-start);
// Write to packet
beaconPacket.ssid = ssid;
}
else if (type == PacketType::ProbeRequest){
// Create ProbeRequestPacket from packet
ProbeRequestPacket probeRequestPacket = ProbeRequestPacket(packet);
packet = probeRequestPacket; // Overwrite packet
// Find probe-request
int start = textHeader.find('(')+1;
std::string requestSsid = textHeader.substr(start, textHeader.find(')')-start);
// Write to packet
probeRequestPacket.requestSsid = requestSsid;
}
else if (type == PacketType::ProbeResponse){
// Create ProbeResponsePacket from packet
ProbeResponsePacket probeResponsePacket = ProbeResponsePacket(packet);
packet = probeResponsePacket; // Overwrite packet
// Find probe-request
int start = textHeader.find('(')+1;
std::string responseSsid = textHeader.substr(start, textHeader.find(')')-start);
// Write to packet
probeResponsePacket.responseSsid = responseSsid;
}
}
void parsePayload(Packet &packet, const std::vector<std::string> &textPacket){
// Expect max of 16byte per line of payload
unsigned int payloadSize = 16*(textPacket.size()-1);
// Go through last line
int line = textPacket.size()-1, charPos;
for(int f=0; f<8*2; ++f){
charPos = 10 + (f/2.0*5);
if(textPacket[line][charPos] == ' ') { // When our char is space, no more data is present
// Set size
payloadSize = 16*(textPacket.size()-2)+f;
break;
}
}
packet.payloadSize = payloadSize;
}
#endif /* EE781A91_6D07_47AC_B3C4_F99E29F3731F */

@ -0,0 +1,31 @@
#ifndef B89BC3C5_AD59_4765_AA06_8110111D316F
#define B89BC3C5_AD59_4765_AA06_8110111D316F
#include <cstdio>
#include <stdexcept>
/// @brief Executes given command and optionally sends buffer to handler
/// @param cmd is the command
/// @param handler is the handler(char*)-function
/// @return Return-code form command
int exec(const char* cmd, void (*handler)(const char*) = nullptr){
const int buf_size = 512;
char buf[buf_size];
// Open execution-pipe
FILE *pipe = popen(cmd, "r");
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buf, buf_size, pipe) != nullptr) {
// When a handler is specified, call it
if(handler != nullptr) (*handler)(buf);
}
// Close pipe and read exit-code
return WEXITSTATUS(pclose(pipe));
}
#endif /* B89BC3C5_AD59_4765_AA06_8110111D316F */

@ -0,0 +1,53 @@
#ifndef B6A9DEE0_30C6_4492_AB96_87D9C5C10E8B
#define B6A9DEE0_30C6_4492_AB96_87D9C5C10E8B
#include <string>
#include <vector>
/// @brief Internal function
void prepare(const int &size, int &start, const int &offset, int &end){
// Set missing fields
if(!end) end = size;
// Edit start/end according to offset
if(offset < 0)
start += offset;
else if(offset > 0)
end -= offset;
}
/// @brief Find str-index based on contains-content
/// @param data is the vector-string-data to search
/// @param strContains string to find
/// @param start where to start searching
/// @param offset search offset to position (results in index being shifted by -offset)
/// @param end where to end searching
/// @return index of found index (with offset if any)
int findContains(const std::vector<std::string> &data, const std::string &strContains, int start = 0, int offset = 0, int end = 0){
prepare(data.size(), start, offset, end);
for(int i=start; i<data.size()-offset; ++i){
if(!data[i+offset].find(strContains))
return i;
}
return -1;
}
/// @brief Find str-index based on exact-content
/// @param data is the vector-string-data to search
/// @param strIs string to find (exact)
/// @param start where to start searching
/// @param offset search offset to position (results in index being shifted by -offset)
/// @param end where to end searching
/// @return index of found index (with offset if any)
int findIs(const std::vector<std::string> &data, const std::string &strIs, int start = 0, int offset = 0, int end = 0){
prepare(data.size(), start, offset, end);
for(int i=start; i<data.size()-offset; ++i){
if(data[i+offset] == strIs)
return i;
}
return -1;
}
#endif /* B6A9DEE0_30C6_4492_AB96_87D9C5C10E8B */

@ -0,0 +1,34 @@
#ifndef F7CFE6A7_34BF_4E04_94CF_DB8374980631
#define F7CFE6A7_34BF_4E04_94CF_DB8374980631
#include <vector>
#include <string>
#include <sstream>
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
char hex_char_to_int(const char &c) {
unsigned char result = 0;
if( ('0' <= c) && (c <= '9') ) {
result = c - '0';
}
else if( ('A' <= c) && (c <= 'F') ) {
result = 10 + c - 'A';
}
else if( ('a' <= c) && (c <= 'f') ) {
result = 10 + c - 'a';
}
return result;
}
#endif /* F7CFE6A7_34BF_4E04_94CF_DB8374980631 */

@ -0,0 +1,36 @@
#ifndef CC724CA7_8BB8_43B9_8A9A_54BD880A76AA
#define CC724CA7_8BB8_43B9_8A9A_54BD880A76AA
uint64_t convertStringToTimestampMicros(std::string textTimestamp){
uint64_t timestamp;
std::tm t = {};
std::istringstream ssTimestamp = std::istringstream(textTimestamp);
if (ssTimestamp >> std::get_time(&t, "%H:%M:%S"))
{
// Get current time
std::time_t curT = std::time(0);
std::tm* curTime = std::localtime(&curT);
// Set missing fields
t.tm_mday = curTime->tm_mday;
t.tm_mon = curTime->tm_mon;
t.tm_year = curTime->tm_year;
t.tm_zone = curTime->tm_zone;
// Convert tm to time
std::time_t time = std::mktime(&t);
// Get micros
int micros = std::stoi(textTimestamp.substr(9, 6));
// Calculate timestamp epoch in micros
timestamp = time*1000000 + micros;
return timestamp;
}
else
{
throw std::runtime_error("Could not parse time: '"+ textTimestamp +"'");
}
}
#endif /* CC724CA7_8BB8_43B9_8A9A_54BD880A76AA */

@ -0,0 +1,15 @@
#ifndef C437A277_1F23_496D_9B69_A21D771ECA91
#define C437A277_1F23_496D_9B69_A21D771ECA91
#include <vector>
#include <limits.h>
int max(std::vector<int> vec){
int max = INT_MIN;
for(int i=0; i<vec.size(); ++i){
if(vec[i] > max) max = vec[i];
}
return max;
}
#endif /* C437A277_1F23_496D_9B69_A21D771ECA91 */

@ -0,0 +1,26 @@
#include <stdio.h>
#include <string>
#include "./helper/exec.hpp"
#include "./handler/bufHandler.hpp"
const std::string tcpdump_baseCmd = "tcpdump -vvv -e -n -X -s0 -i ";
int main(int argc, char *args[]){
std::string tcpdump_cmd;
if(argc == 2){
tcpdump_cmd = tcpdump_baseCmd + args[1];
} else {
fprintf(stderr, "Missing interface\n");
exit(1);
}
int exitCode = exec(tcpdump_cmd.c_str(), &bufHandler);
if(exitCode){
fprintf(stderr, "\ntcpdump exited with non-zero ExitCode: %d\n Something went wrong! Check tcpdump-output for more information.\n", exitCode);
exit(1);
}
return 0;
}
Loading…
Cancel
Save