diff --git a/YSFReflector/BlockList.cpp b/YSFReflector/BlockList.cpp new file mode 100644 index 0000000..2e0de0d --- /dev/null +++ b/YSFReflector/BlockList.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 by Jonathan Naylor G4KLX + * + * 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 "BlockList.h" +#include "YSFDefines.h" +#include "Log.h" + +#include + +#include +#include + +const int BUFFER_SIZE = 500; + +CBlockList::CBlockList(const std::string& file, unsigned int time) : +m_file(file), +m_time(time), +m_callsigns(), +m_timer(1000U, time * 60U), +m_checksum(0U) +{ +} + +CBlockList::~CBlockList() +{ +} + +bool CBlockList::start() +{ + loadFile(); + + m_timer.start(); + + return true; +} + +bool CBlockList::check(const unsigned char* callsign) const +{ + assert(callsign != NULL); + + std::string call = std::string((char*)callsign, YSF_CALLSIGN_LENGTH); + std::for_each(call.begin(), call.end(), [](char& c) { + c = std::toupper(c); + }); + + for (std::vector::const_iterator it = m_callsigns.cbegin(); it != m_callsigns.cend(); ++it) { + const std::string blocked = *it; + if (call.find(blocked) != std::string::npos) + return false; + } + + return true; +} + +void CBlockList::clock(unsigned int ms) +{ + m_timer.clock(ms); + + if (m_timer.isRunning() && m_timer.hasExpired()) { + loadFile(); + m_timer.start(); + } +} + +bool CBlockList::loadFile() +{ + FILE* fp = ::fopen(m_file.c_str(), "rt"); + if (fp == NULL) + return false; + + char buffer[BUFFER_SIZE]; + + // First perform the checksum (Fletcher 16) + uint16_t sum1 = 0U; + uint16_t sum2 = 0U; + while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) { + for (char* p = buffer; *p != '\0'; p++) { + sum1 = (sum1 + uint8_t(*p)) % 255U; + sum2 = (sum2 + sum1) % 255U; + } + } + + uint16_t checksum = (sum2 << 8) | sum1; + if (checksum == m_checksum) { + ::fclose(fp); + return false; + } + + m_checksum = checksum; + + // Rewind the file + ::fseek(fp, 0L, SEEK_SET); + + // Read the callsigns into the array + m_callsigns.clear(); + unsigned int n = 0U; + + while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) { + char* p; + if ((p = ::strchr(buffer, '\n')) != NULL) + *p = '\0'; + if ((p = ::strchr(buffer, '\r')) != NULL) + *p = '\0'; + + if (::strlen(buffer) > 0U) { + std::string callsign = std::string(buffer); + + std::for_each(callsign.begin(), callsign.end(), [](char& c) { + c = std::toupper(c); + }); + + m_callsigns.push_back(callsign); + n++; + } + } + + ::fclose(fp); + + LogInfo("Loaded %u callsigns from the block list", n); + + return true; +} diff --git a/YSFReflector/BlockList.h b/YSFReflector/BlockList.h new file mode 100644 index 0000000..3ddbcbb --- /dev/null +++ b/YSFReflector/BlockList.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 by Jonathan Naylor G4KLX + * + * 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(BLOCKLIST_H) +#define BLOCKLIST_H + +#include "Timer.h" + +#include +#include +#include + +class CBlockList +{ +public: + CBlockList(const std::string& file, unsigned int time); + ~CBlockList(); + + bool start(); + + bool check(const unsigned char* callsign) const; + + void clock(unsigned int ms); + +private: + std::string m_file; + unsigned int m_time; + std::vector m_callsigns; + CTimer m_timer; + uint16_t m_checksum; + + bool loadFile(); +}; + +#endif diff --git a/YSFReflector/Conf.cpp b/YSFReflector/Conf.cpp index 9c6bd2f..cba5370 100644 --- a/YSFReflector/Conf.cpp +++ b/YSFReflector/Conf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -31,7 +31,8 @@ enum SECTION { SECTION_GENERAL, SECTION_INFO, SECTION_LOG, - SECTION_NETWORK + SECTION_NETWORK, + SECTION_BLOCKLIST }; CConf::CConf(const std::string& file) : @@ -46,7 +47,9 @@ m_logFilePath(), m_logFileRoot(), m_logFileRotate(true), m_networkPort(0U), -m_networkDebug(false) +m_networkDebug(false), +m_blockListFile(), +m_blockListTime(5U) { } @@ -78,6 +81,8 @@ bool CConf::read() section = SECTION_LOG; else if (::strncmp(buffer, "[Network]", 9U) == 0) section = SECTION_NETWORK; + else if (::strncmp(buffer, "[Block List]", 12U) == 0) + section = SECTION_BLOCKLIST; else section = SECTION_NONE; @@ -135,6 +140,11 @@ bool CConf::read() m_networkPort = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_networkDebug = ::atoi(value) == 1; + } else if (section == SECTION_BLOCKLIST) { + if (::strcmp(key, "File") == 0) + m_blockListFile = value; + else if (::strcmp(key, "Time") == 0) + m_blockListTime = (unsigned int)::atoi(value); } } @@ -198,3 +208,12 @@ bool CConf::getNetworkDebug() const return m_networkDebug; } +std::string CConf::getBlockListFile() const +{ + return m_blockListFile; +} + +unsigned int CConf::getBlockListTime() const +{ + return m_blockListTime; +} diff --git a/YSFReflector/Conf.h b/YSFReflector/Conf.h index f9e1732..e21ccc5 100644 --- a/YSFReflector/Conf.h +++ b/YSFReflector/Conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -49,6 +49,10 @@ public: unsigned int getNetworkPort() const; bool getNetworkDebug() const; + // The Block List section + std::string getBlockListFile() const; + unsigned int getBlockListTime() const; + private: std::string m_file; bool m_daemon; @@ -65,6 +69,9 @@ private: unsigned int m_networkPort; bool m_networkDebug; + + std::string m_blockListFile; + unsigned int m_blockListTime; }; #endif diff --git a/YSFReflector/Makefile b/YSFReflector/Makefile index db9d0bb..2676fc1 100644 --- a/YSFReflector/Makefile +++ b/YSFReflector/Makefile @@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DUDP_SOCKET_MAX=2 LIBS = -lpthread LDFLAGS = -g -OBJECTS = Conf.o Log.o Network.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o YSFReflector.o +OBJECTS = BlockList.o Conf.o Log.o Network.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o YSFReflector.o all: YSFReflector diff --git a/YSFReflector/Version.h b/YSFReflector/Version.h index 23a8298..75c23cd 100644 --- a/YSFReflector/Version.h +++ b/YSFReflector/Version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20201124"; +const char* VERSION = "20210213"; #endif diff --git a/YSFReflector/YSFReflector.cpp b/YSFReflector/YSFReflector.cpp index af653d9..a5b0a1c 100644 --- a/YSFReflector/YSFReflector.cpp +++ b/YSFReflector/YSFReflector.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2018,2020,2021 by Jonathan Naylor G4KLX * * 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 @@ -17,6 +17,7 @@ */ #include "YSFReflector.h" +#include "BlockList.h" #include "StopWatch.h" #include "Network.h" #include "Version.h" @@ -175,7 +176,10 @@ void CYSFReflector::run() ::LogFinalise(); return; } - + + CBlockList blockList(m_conf.getBlockListFile(), m_conf.getBlockListTime()); + blockList.start(); + network.setCount(0); CStopWatch stopWatch; @@ -231,37 +235,42 @@ void CYSFReflector::run() } network.setCount(m_repeaters.size()); } else if (::memcmp(buffer + 0U, "YSFD", 4U) == 0 && rpt != NULL) { - if (!watchdogTimer.isRunning()) { - ::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH); + // Is this user allowed? + if (blockList.check(buffer + 14U)) { + if (!watchdogTimer.isRunning()) { + ::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH); - if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0) - ::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH); - else - ::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH); - - if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0) - ::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH); - else - ::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH); - - LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); - } else { - if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) { - bool changed = false; - - if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) { + if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0) ::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH); - changed = true; - } + else + ::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH); - if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) { + if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0) ::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH); - changed = true; + else + ::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH); + + LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); + } else { + if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) { + bool changed = false; + + if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) { + ::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH); + changed = true; + } + + if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) { + ::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH); + changed = true; + } + + if (changed) + LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); } - - if (changed) - LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); } + } else { + LogDebug("Data from %10.10s at %10.10s blocked", buffer + 14U, buffer + 4U); } watchdogTimer.start(); @@ -317,6 +326,8 @@ void CYSFReflector::run() dumpTimer.start(); } + blockList.clock(ms); + if (ms < 5U) CThread::sleep(5U); } diff --git a/YSFReflector/YSFReflector.ini b/YSFReflector/YSFReflector.ini index 35f1be7..f2cd2cc 100644 --- a/YSFReflector/YSFReflector.ini +++ b/YSFReflector/YSFReflector.ini @@ -20,3 +20,6 @@ FileRotate=1 Port=42000 Debug=0 +[Block List] +File=BlockList.txt +Time=5 diff --git a/YSFReflector/YSFReflector.vcxproj b/YSFReflector/YSFReflector.vcxproj index 6382add..cd80b58 100644 --- a/YSFReflector/YSFReflector.vcxproj +++ b/YSFReflector/YSFReflector.vcxproj @@ -146,6 +146,7 @@ + @@ -159,6 +160,7 @@ + diff --git a/YSFReflector/YSFReflector.vcxproj.filters b/YSFReflector/YSFReflector.vcxproj.filters index a76cd78..e31c4ed 100644 --- a/YSFReflector/YSFReflector.vcxproj.filters +++ b/YSFReflector/YSFReflector.vcxproj.filters @@ -44,6 +44,9 @@ Header Files + + Header Files + @@ -73,5 +76,8 @@ Source Files + + Source Files + \ No newline at end of file