diff --git a/Conf.cpp b/Conf.cpp index 1ea9f82..d532d5c 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -37,6 +37,8 @@ CConf::CConf(const std::string& file) : m_file(file), m_callsign(), m_whiteList(), +m_blacklistRegexfile(), +m_whitelistRegexfile(), m_rptAddress(), m_rptPort(0U), m_myAddress(), @@ -105,7 +107,11 @@ bool CConf::read() m_whiteList.push_back(ric); p = ::strtok(NULL, ",\r\n"); } - } else if (::strcmp(key, "RptAddress") == 0) + } else if (::strcmp(key,"BlacklistRegexfile") == 0) + m_blacklistRegexfile = value; + else if (::strcmp(key,"WhitelistRegexfile") == 0) + m_whitelistRegexfile = value; + else if (::strcmp(key, "RptAddress") == 0) m_rptAddress = value; else if (::strcmp(key, "RptPort") == 0) m_rptPort = (unsigned int)::atoi(value); @@ -155,6 +161,16 @@ std::vector CConf::getWhiteList() const return m_whiteList; } +std::string CConf::getblacklistRegexfile() const +{ + return m_blacklistRegexfile; +} + +std::string CConf::getwhitelistRegexfile() const +{ + return m_whitelistRegexfile; +} + std::string CConf::getRptAddress() const { return m_rptAddress; diff --git a/Conf.h b/Conf.h index 4a8378a..bd3be30 100644 --- a/Conf.h +++ b/Conf.h @@ -33,6 +33,8 @@ public: // The General section std::string getCallsign() const; std::vector getWhiteList() const; + std::string getblacklistRegexfile() const; + std::string getwhitelistRegexfile() const; std::string getRptAddress() const; unsigned int getRptPort() const; std::string getMyAddress() const; @@ -56,6 +58,8 @@ private: std::string m_callsign; std::vector m_whiteList; + std::string m_blacklistRegexfile; + std::string m_whitelistRegexfile; std::string m_rptAddress; unsigned int m_rptPort; std::string m_myAddress; diff --git a/DAPNETGateway.cpp b/DAPNETGateway.cpp index bf520b2..60b3745 100644 --- a/DAPNETGateway.cpp +++ b/DAPNETGateway.cpp @@ -22,6 +22,8 @@ #include "Thread.h" #include "Timer.h" #include "Log.h" +#include "REGEX.h" +#include #if defined(_WIN32) || defined(_WIN64) #include @@ -108,6 +110,8 @@ m_schedule(NULL), m_allSlots(false), m_currentSlot(0U), m_sentCodewords(0U), +m_regexBlacklist(), +m_regexWhitelist(), m_mmdvmFree(false) { } @@ -263,6 +267,18 @@ int CDAPNETGateway::run() } std::vector whiteList = m_conf.getWhiteList(); + std::vector regexBlacklist; + std::vector regexWhitelist; + + m_regexBlacklist = new CREGEX(m_conf.getblacklistRegexfile()); + if (m_regexBlacklist->load()) + regexBlacklist = m_regexBlacklist->get(); + + m_regexWhitelist = new CREGEX(m_conf.getwhitelistRegexfile()); + if (m_regexWhitelist->load()) + regexWhitelist = m_regexWhitelist->get(); + + for (;;) { unsigned char buffer[200U]; @@ -296,12 +312,39 @@ int CDAPNETGateway::run() CPOCSAGMessage* message = m_dapnetNetwork->readMessage(); if (message != NULL) { bool found = true; + bool blacklistRegexmatch = false; + bool whitelistRegexmatch = true; // If we have a white list of RICs, use it. if (!whiteList.empty()) found = std::find(whiteList.begin(), whiteList.end(), message->m_ric) != whiteList.end(); + + std::string messageBody(reinterpret_cast(message->m_message)); + //If we have a list of blacklist REGEXes, use them + if (!regexBlacklist.empty()) { + for (std::regex regex : regexBlacklist) { + bool ret = std::regex_match(messageBody,regex); + //If the regex matches the message body, don't send the message + if (ret) { + blacklistRegexmatch = true; + LogDebug("Blacklist REGEX match: Not queueing message to %07u, type %u, message: \"%.*s\"", message->m_ric, message->m_type, message->m_length, messageBody.c_str()); + } + } + } - if (found) { + if(!regexWhitelist.empty() && !blacklistRegexmatch) { + for (std::regex regex : regexWhitelist) { + bool ret = std::regex_match(messageBody,regex); + //If the regex does not match the message body, don't send the message + if (!ret) { + whitelistRegexmatch = false; + LogDebug("No whitelist REGEX match: Not queueing message to %07u, type %u, message: \"%.*s\"", message->m_ric, message->m_type, message->m_length, messageBody.c_str()); + } + } + + } + + if (found && !blacklistRegexmatch && whitelistRegexmatch) { switch (message->m_functional) { case FUNCTIONAL_ALPHANUMERIC: LogDebug("Queueing message to %07u, type %u, func Alphanumeric: \"%.*s\"", message->m_ric, message->m_type, message->m_length, message->m_message); diff --git a/DAPNETGateway.h b/DAPNETGateway.h index f5c338b..3b29a3e 100644 --- a/DAPNETGateway.h +++ b/DAPNETGateway.h @@ -24,10 +24,12 @@ #include "POCSAGMessage.h" #include "StopWatch.h" #include "Conf.h" +#include "REGEX.h" #include #include #include +#include class CDAPNETGateway { @@ -47,6 +49,8 @@ private: bool m_allSlots; unsigned int m_currentSlot; unsigned int m_sentCodewords; + CREGEX* m_regexBlacklist; + CREGEX* m_regexWhitelist; bool m_mmdvmFree; @@ -56,6 +60,9 @@ private: unsigned int calculateCodewords(const CPOCSAGMessage* message) const; void loadSchedule(); bool sendMessage(CPOCSAGMessage* message) const; + +// std::vector m_regexBlacklist; +// std::vector m_regexWhitelist; }; #endif diff --git a/DAPNETGateway.ini b/DAPNETGateway.ini index 104fddf..fe9abba 100644 --- a/DAPNETGateway.ini +++ b/DAPNETGateway.ini @@ -1,6 +1,8 @@ [General] Callsign=g9bf # WhiteList=12345,78901 +#BlacklistRegexfile=/tmp/blregexes.txt +#WhitelistRegexfile=/tmp/wlregexes.txt RptAddress=127.0.0.1 RptPort=3800 LocalAddress=127.0.0.1 diff --git a/Makefile b/Makefile index c29d512..c13b5da 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lm -lpthread LDFLAGS = -g -OBJECTS = Conf.o DAPNETGateway.o DAPNETNetwork.o Log.o POCSAGMessage.o POCSAGNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o +OBJECTS = Conf.o DAPNETGateway.o DAPNETNetwork.o Log.o POCSAGMessage.o POCSAGNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o REGEX.o all: DAPNETGateway diff --git a/README.REGEX b/README.REGEX new file mode 100644 index 0000000..9bce991 --- /dev/null +++ b/README.REGEX @@ -0,0 +1,21 @@ +The REGEX functionality allows you to whitelist or blacklist messages based on +pattern matching the message body itself (not the RIC). + +The options for this are: + + +WhitelistRegexfile= +BlacklistRegexfile= + +REGEXs are placed in the the respective textfile, one per line. These need to +be a full match, i.e. they need to match the entire message, begining with ^ +and ending with $. + +For example: + +^NAGIOS.*$ - matches all Nagios alerts + +^(G|M|2).+$ - Matches messages with the first character as a G.M or 2 - i.e. +match all UK callsigns. + + diff --git a/REGEX.cpp b/REGEX.cpp new file mode 100644 index 0000000..9653f27 --- /dev/null +++ b/REGEX.cpp @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX +* +* Contributed by Simon G7RZU +* +* 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "REGEX.h" +#include "Log.h" + +#include +#include + +CREGEX::CREGEX(const std::string& regexFile) : +m_regexFile(regexFile), +m_regex() +{ +} + +bool CREGEX::load() +{ + FILE* fp = ::fopen(m_regexFile.c_str(), "rt"); + if (fp != NULL) { + char buffer[100U]; + std::regex regex; + while (::fgets(buffer, 100U, fp) != NULL) { + if (buffer[0U] == '#') + continue; + + const char* regexStr = ::strtok(buffer, "\r\n"); + + if (regexStr != NULL) { + try { + regex = std::regex(regexStr); + } + + catch(const std::regex_error& e) { + LogDebug("error in regex %s (%s), skipping",regexStr,e.what()); + continue; + } + m_regex.push_back(regex); + } + } + + ::fclose(fp); + } + + size_t size = m_regex.size(); + LogInfo("Loaded %u REGEX from file %s", size, m_regexFile.c_str()); + + size = m_regex.size(); + if (size == 0U) + return false; + + return true; +} + +std::vector CREGEX::get() +{ + return(m_regex); +} diff --git a/REGEX.h b/REGEX.h new file mode 100644 index 0000000..a1888bb --- /dev/null +++ b/REGEX.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX +* +* Contributed by Simon G7RZU +* +* 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(REGEX_H) +#define REGEX_H + + +#include +#include +#include + +class CREGEX { +public: + + std::vector get(); + bool load(); + CREGEX(const std::string& regexFile); + ~CREGEX(); + +private: + + std::string m_regexFile; + std::vector m_regex; +}; + +#endif