From f64198999176e5498aa1293e55741f3161c04540 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 16 May 2016 16:47:18 +0200 Subject: [PATCH] Added maxconnsperip setting to controller. Only enforced if USER_NEW trigger is in use. --- lib/stream.cpp | 2 +- src/controller/controller.cpp | 2 ++ src/controller/controller_statistics.cpp | 27 ++++++++++++++++++++++-- src/controller/controller_statistics.h | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/stream.cpp b/lib/stream.cpp index d00084ac..c93399ec 100644 --- a/lib/stream.cpp +++ b/lib/stream.cpp @@ -322,7 +322,7 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir /// Attempt to start a push for streamname to target. /// Both streamname and target may be changed by this function: /// - streamname is sanitized to a permissible streamname -/// - target gets variables replaced and may be altered by the RECORDING_START trigger response. +/// - target gets variables replaced and may be altered by the PUSH_OUT_START trigger response. /// Attempts to match the altered target to an output that can push to it. pid_t Util::startPush(std::string & streamname, std::string & target) { diff --git a/src/controller/controller.cpp b/src/controller/controller.cpp index 3cd60a8b..8ac9513f 100644 --- a/src/controller/controller.cpp +++ b/src/controller/controller.cpp @@ -167,6 +167,7 @@ int main(int argc, char ** argv){ Controller::conf.addOption("port", stored_port); Controller::conf.addOption("interface", stored_interface); Controller::conf.addOption("username", stored_user); + Controller::conf.addOption("maxconnsperip", JSON::fromString("{\"long\":\"maxconnsperip\", \"short\":\"M\", \"arg\":\"integer\" \"default\":0, \"help\":\"Max simultaneous sessions per unique IP address. Only enforced if the USER_NEW trigger is in use.\"}")); Controller::conf.addOption("account", JSON::fromString("{\"long\":\"account\", \"short\":\"a\", \"arg\":\"string\" \"default\":\"\", \"help\":\"A username:password string to create a new account with.\"}")); Controller::conf.addOption("logfile", JSON::fromString("{\"long\":\"logfile\", \"short\":\"L\", \"arg\":\"string\" \"default\":\"\",\"help\":\"Redirect all standard output to a log file, provided with an argument\"}")); Controller::conf.addOption("configFile", JSON::fromString("{\"long\":\"config\", \"short\":\"c\", \"arg\":\"string\" \"default\":\"config.json\", \"help\":\"Specify a config file other than default.\"}")); @@ -230,6 +231,7 @@ int main(int argc, char ** argv){ if (Controller::Storage["config"]["controller"]["prometheus"]){ Controller::conf.getOption("prometheus", true)[0u] = Controller::Storage["config"]["controller"]["prometheus"]; } + Controller::maxConnsPerIP = Controller::conf.getInteger("maxconnsperip"); Controller::Storage["config"]["controller"]["prometheus"] = Controller::conf.getString("prometheus"); { IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1); diff --git a/src/controller/controller_statistics.cpp b/src/controller/controller_statistics.cpp index 8913316a..1dab4802 100644 --- a/src/controller/controller_statistics.cpp +++ b/src/controller/controller_statistics.cpp @@ -39,6 +39,7 @@ std::map Controller::connToSession; ///< M bool Controller::killOnExit = KILL_ON_EXIT; tthread::mutex Controller::statsMutex; std::map Controller::activeStreams; +unsigned int Controller::maxConnsPerIP = 0; //For server-wide totals. Local to this file only. struct streamTotals { @@ -190,9 +191,31 @@ void Controller::SharedMemStats(void * config){ /// Updates the given active connection with new stats data. void Controller::statSession::update(unsigned long index, IPC::statExchange & data){ - //update the sync byte: 0 = requesting fill, 1 = needs checking, > 1 = state known + //update the sync byte: 0 = requesting fill, 1 = needs checking, > 1 = state known (100=denied, 10=accepted) if (!data.getSync()){ - data.setSync(sync); + //if we have a maximum connection count per IP, enforce it + if (maxConnsPerIP){ + unsigned int currConns = 1; + long long shortly = Util::epoch(); + std::string myHost; + { + sessIndex tmpidx(data); + myHost = tmpidx.host; + } + for (std::map::iterator it = sessions.begin(); it != sessions.end(); it++){ + + if (&it->second != this && it->first.host == myHost && (it->second.hasDataFor(shortly-STATS_DELAY) || it->second.hasDataFor(shortly) || it->second.hasDataFor(shortly-1) || it->second.hasDataFor(shortly-2) || it->second.hasDataFor(shortly-3) || it->second.hasDataFor(shortly-4) || it->second.hasDataFor(shortly-5)) && ++currConns > maxConnsPerIP){break;} + } + if (currConns > maxConnsPerIP){ + WARN_MSG("Disconnecting session from %s: exceeds max connection count of %u", myHost.c_str(), maxConnsPerIP); + data.setSync(100); + }else{ + data.setSync(sync); + } + }else{ + //no maximum, just set the sync byte to its current value + data.setSync(sync); + } }else{ if (sync < 2){ sync = data.getSync(); diff --git a/src/controller/controller_statistics.h b/src/controller/controller_statistics.h index 92d620c2..c29def5f 100644 --- a/src/controller/controller_statistics.h +++ b/src/controller/controller_statistics.h @@ -16,6 +16,7 @@ namespace Controller { extern bool killOnExit; + extern unsigned int maxConnsPerIP; //These functions keep track of which streams are currently active. extern std::map activeStreams;