]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/rscript/rscript.cpp
Install Boost in GitHub Actions.
[stg.git] / projects / stargazer / plugins / other / rscript / rscript.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
20  */
21
22 #include "rscript.h"
23
24 #include "ur_functor.h"
25
26 #include "stg/common.h"
27 #include "stg/locker.h"
28 #include "stg/users.h"
29 #include "stg/user_property.h"
30 #include "stg/logger.h"
31
32 #include <algorithm>
33
34 #include <csignal>
35 #include <cassert>
36 #include <cstdlib>
37 #include <cerrno>
38 #include <cstring>
39
40 #include <sys/time.h>
41 #include <netinet/ip.h>
42
43 #define RS_DEBUG (1)
44 #define MAX_SHORT_PCKT  (3)
45
46 extern volatile time_t stgTime;
47
48 using RS::REMOTE_SCRIPT;
49
50 namespace {
51
52 template<typename T>
53 struct USER_IS
54 {
55     explicit USER_IS(RS::UserPtr u) : user(u) {}
56     bool operator()(const T & notifier) { return notifier.GetUser() == user; }
57
58     RS::UserPtr user;
59 };
60
61 } // namespace anonymous
62
63 extern "C" STG::Plugin* GetPlugin()
64 {
65     static REMOTE_SCRIPT plugin;
66     return &plugin;
67 }
68 //-----------------------------------------------------------------------------
69 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
71 RS::SETTINGS::SETTINGS()
72     : sendPeriod(0),
73       port(0)
74 {
75 }
76 //-----------------------------------------------------------------------------
77 int RS::SETTINGS::ParseSettings(const STG::ModuleSettings & s)
78 {
79 int p;
80 STG::ParamValue pv;
81 netRouters.clear();
82 ///////////////////////////
83 pv.param = "Port";
84 auto pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
85 if (pvi == s.moduleParams.end() || pvi->value.empty())
86     {
87     errorStr = "Parameter \'Port\' not found.";
88     printfd(__FILE__, "Parameter 'Port' not found\n");
89     return -1;
90     }
91 if (ParseIntInRange(pvi->value[0], 2, 65535, &p) != 0)
92     {
93     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
94     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
95     return -1;
96     }
97 port = static_cast<uint16_t>(p);
98 ///////////////////////////
99 pv.param = "SendPeriod";
100 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
101 if (pvi == s.moduleParams.end() || pvi->value.empty())
102     {
103     errorStr = "Parameter \'SendPeriod\' not found.";
104     printfd(__FILE__, "Parameter 'SendPeriod' not found\n");
105     return -1;
106     }
107
108 if (ParseIntInRange(pvi->value[0], 5, 600, &sendPeriod) != 0)
109     {
110     errorStr = "Cannot parse parameter \'SendPeriod\': " + errorStr;
111     printfd(__FILE__, "Cannot parse parameter 'SendPeriod'\n");
112     return -1;
113     }
114 ///////////////////////////
115 pv.param = "UserParams";
116 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
117 if (pvi == s.moduleParams.end() || pvi->value.empty())
118     {
119     errorStr = "Parameter \'UserParams\' not found.";
120     printfd(__FILE__, "Parameter 'UserParams' not found\n");
121     return -1;
122     }
123 userParams = pvi->value;
124 ///////////////////////////
125 pv.param = "Password";
126 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
127 if (pvi == s.moduleParams.end() || pvi->value.empty())
128     {
129     errorStr = "Parameter \'Password\' not found.";
130     printfd(__FILE__, "Parameter 'Password' not found\n");
131     return -1;
132     }
133 password = pvi->value[0];
134 ///////////////////////////
135 pv.param = "SubnetFile";
136 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
137 if (pvi == s.moduleParams.end() || pvi->value.empty())
138     {
139     errorStr = "Parameter \'SubnetFile\' not found.";
140     printfd(__FILE__, "Parameter 'SubnetFile' not found\n");
141     return -1;
142     }
143 subnetFile = pvi->value[0];
144
145 NRMapParser nrMapParser;
146
147 if (!nrMapParser.ReadFile(subnetFile))
148     netRouters = nrMapParser.GetMap();
149 else
150     STG::PluginLogger::get("rscript")("mod_rscript: error opening subnets file '%s'", subnetFile.c_str());
151
152 return 0;
153 }
154 //-----------------------------------------------------------------------------
155 //-----------------------------------------------------------------------------
156 //-----------------------------------------------------------------------------
157 REMOTE_SCRIPT::REMOTE_SCRIPT()
158     : sendPeriod(15),
159       halfPeriod(8),
160       isRunning(false),
161       users(nullptr),
162       sock(0),
163       onAddUserNotifier(*this),
164       onDelUserNotifier(*this),
165       logger(STG::PluginLogger::get("rscript"))
166 {
167 }
168 //-----------------------------------------------------------------------------
169 void REMOTE_SCRIPT::Run(std::stop_token token)
170 {
171 sigset_t signalSet;
172 sigfillset(&signalSet);
173 pthread_sigmask(SIG_BLOCK, &signalSet, nullptr);
174
175 isRunning = true;
176
177 while (!token.stop_requested())
178     {
179     PeriodicSend();
180     sleep(2);
181     }
182
183 isRunning = false;
184 }
185 //-----------------------------------------------------------------------------
186 int REMOTE_SCRIPT::ParseSettings()
187 {
188 auto ret = rsSettings.ParseSettings(settings);
189 if (ret != 0)
190     errorStr = rsSettings.GetStrError();
191
192 sendPeriod = rsSettings.GetSendPeriod();
193 halfPeriod = sendPeriod / 2;
194
195 return ret;
196 }
197 //-----------------------------------------------------------------------------
198 int REMOTE_SCRIPT::Start()
199 {
200 netRouters = rsSettings.GetSubnetsMap();
201
202 InitEncrypt(rsSettings.GetPassword());
203
204 users->AddNotifierUserAdd(&onAddUserNotifier);
205 users->AddNotifierUserDel(&onDelUserNotifier);
206
207 if (GetUsers())
208     return -1;
209
210 if (PrepareNet())
211     return -1;
212
213 if (!isRunning)
214     m_thread = std::jthread([this](auto token){ Run(std::move(token)); });
215
216 errorStr = "";
217 return 0;
218 }
219 //-----------------------------------------------------------------------------
220 int REMOTE_SCRIPT::Stop()
221 {
222 if (!IsRunning())
223     return 0;
224
225 m_thread.request_stop();
226
227 std::for_each(
228         authorizedUsers.begin(),
229         authorizedUsers.end(),
230         DisconnectUser(*this)
231         );
232
233 FinalizeNet();
234
235 if (isRunning)
236     {
237     //5 seconds to thread stops itself
238     for (int i = 0; i < 25 && isRunning; i++)
239         {
240         struct timespec ts = {0, 200000000};
241         nanosleep(&ts, nullptr);
242         }
243     }
244
245 users->DelNotifierUserDel(&onDelUserNotifier);
246 users->DelNotifierUserAdd(&onAddUserNotifier);
247
248 if (isRunning)
249     {
250     logger("Cannot stop thread.");
251     m_thread.detach();
252     }
253 else
254     m_thread.join();
255
256 return 0;
257 }
258 //-----------------------------------------------------------------------------
259 int REMOTE_SCRIPT::Reload(const STG::ModuleSettings & /*ms*/)
260 {
261 NRMapParser nrMapParser;
262
263 if (nrMapParser.ReadFile(rsSettings.GetMapFileName()))
264     {
265     errorStr = nrMapParser.GetErrorStr();
266     logger("Map file reading error: %s", errorStr.c_str());
267     return -1;
268     }
269
270     {
271     std::lock_guard lock(m_mutex);
272
273     printfd(__FILE__, "REMOTE_SCRIPT::Reload()\n");
274
275     netRouters = nrMapParser.GetMap();
276     }
277
278 std::for_each(authorizedUsers.begin(),
279               authorizedUsers.end(),
280               UpdateRouter(*this));
281
282 logger("%s reloaded successfully.", rsSettings.GetMapFileName().c_str());
283 printfd(__FILE__, "REMOTE_SCRIPT::Reload() %s reloaded successfully.\n");
284
285 return 0;
286 }
287 //-----------------------------------------------------------------------------
288 bool REMOTE_SCRIPT::PrepareNet()
289 {
290 sock = socket(AF_INET, SOCK_DGRAM, 0);
291
292 if (sock < 0)
293     {
294     errorStr = "Cannot create socket.";
295     logger("Canot create a socket: %s", strerror(errno));
296     printfd(__FILE__, "Cannot create socket\n");
297     return true;
298     }
299
300 return false;
301 }
302 //-----------------------------------------------------------------------------
303 bool REMOTE_SCRIPT::FinalizeNet()
304 {
305 close(sock);
306 return false;
307 }
308 //-----------------------------------------------------------------------------
309 void REMOTE_SCRIPT::PeriodicSend()
310 {
311 std::lock_guard lock(m_mutex);
312
313 auto it = authorizedUsers.begin();
314 while (it != authorizedUsers.end())
315     {
316     if (difftime(stgTime, it->second.lastSentTime) - (rand() % halfPeriod) > sendPeriod)
317         {
318         Send(it->second);
319         }
320     ++it;
321     }
322 }
323 //-----------------------------------------------------------------------------
324 #ifdef NDEBUG
325 bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t, RS::USER & rsu, bool forceDisconnect) const
326 #else
327 bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t bufSize, RS::USER & rsu, bool forceDisconnect) const
328 #endif
329 {
330 RS::PACKET_HEADER packetHead;
331
332 memset(packetHead.padding, 0, sizeof(packetHead.padding));
333 memcpy(packetHead.magic, RS_ID, sizeof(RS_ID));
334 packetHead.protoVer[0] = '0';
335 packetHead.protoVer[1] = '2';
336 if (forceDisconnect)
337     {
338     packetHead.packetType = RS_DISCONNECT_PACKET;
339     printfd(__FILE__, "RSCRIPT: force disconnect for '%s'\n", rsu.user->GetLogin().c_str());
340     }
341 else
342     {
343     if (rsu.shortPacketsCount % MAX_SHORT_PCKT == 0)
344         {
345         //SendLong
346         packetHead.packetType = rsu.user->IsInetable() ? RS_CONNECT_PACKET : RS_DISCONNECT_PACKET;
347         if (rsu.user->IsInetable())
348             printfd(__FILE__, "RSCRIPT: connect for '%s'\n", rsu.user->GetLogin().c_str());
349         else
350             printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
351         }
352     else
353         {
354         //SendShort
355         packetHead.packetType = rsu.user->IsInetable() ? RS_ALIVE_PACKET : RS_DISCONNECT_PACKET;
356         if (rsu.user->IsInetable())
357             printfd(__FILE__, "RSCRIPT: alive for '%s'\n", rsu.user->GetLogin().c_str());
358         else
359             printfd(__FILE__, "RSCRIPT: disconnect for '%s'\n", rsu.user->GetLogin().c_str());
360         }
361     }
362 rsu.shortPacketsCount++;
363 rsu.lastSentTime = stgTime;
364
365 packetHead.ip = htonl(rsu.ip);
366 packetHead.id = htonl(rsu.user->GetID());
367 strncpy(reinterpret_cast<char*>(packetHead.login), rsu.user->GetLogin().c_str(), RS_LOGIN_LEN);
368 packetHead.login[RS_LOGIN_LEN - 1] = 0;
369
370 memcpy(buf, &packetHead, sizeof(packetHead));
371
372 if (packetHead.packetType == RS_ALIVE_PACKET)
373     {
374     return false;
375     }
376
377 RS::PACKET_TAIL packetTail;
378
379 memset(packetTail.padding, 0, sizeof(packetTail.padding));
380 memcpy(packetTail.magic, RS_ID, sizeof(RS_ID));
381 std::string params;
382 for (const auto& param : rsSettings.GetUserParams())
383     {
384     auto value = rsu.user->GetParamValue(param);
385     if (params.length() + value.length() > RS_PARAMS_LEN - 1)
386     {
387         logger("Script params string length %d exceeds the limit of %d symbols.", params.length() + value.length(), RS_PARAMS_LEN);
388         break;
389     }
390     params += value + " ";
391     }
392 strncpy(reinterpret_cast<char*>(packetTail.params), params.c_str(), RS_PARAMS_LEN);
393 packetTail.params[RS_PARAMS_LEN - 1] = 0;
394
395 assert(sizeof(packetHead) + sizeof(packetTail) <= bufSize && "Insufficient buffer space");
396
397 Encrypt(buf + sizeof(packetHead), reinterpret_cast<char *>(&packetTail), sizeof(packetTail) / 8);
398
399 return false;
400 }
401 //-----------------------------------------------------------------------------
402 bool REMOTE_SCRIPT::Send(RS::USER & rsu, bool forceDisconnect) const
403 {
404 char buffer[RS_MAX_PACKET_LEN];
405
406 memset(buffer, 0, sizeof(buffer));
407
408 if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
409     {
410     printfd(__FILE__, "REMOTE_SCRIPT::Send() - Invalid packet length!\n");
411     return true;
412     }
413
414 for (const auto& ip : rsu.routers)
415 {
416     struct sockaddr_in sendAddr;
417
418     sendAddr.sin_family = AF_INET;
419     sendAddr.sin_port = htons(rsSettings.GetPort());
420     sendAddr.sin_addr.s_addr = ip;
421
422     return sendto(sock, buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr*>(&sendAddr), sizeof(sendAddr)) > 0;
423 }
424
425 return false;
426 }
427 //-----------------------------------------------------------------------------
428 bool REMOTE_SCRIPT::SendDirect(RS::USER & rsu, uint32_t routerIP, bool forceDisconnect) const
429 {
430 char buffer[RS_MAX_PACKET_LEN];
431
432 if (PreparePacket(buffer, sizeof(buffer), rsu, forceDisconnect))
433     {
434     printfd(__FILE__, "REMOTE_SCRIPT::SendDirect() - Invalid packet length!\n");
435     return true;
436     }
437
438 struct sockaddr_in sendAddr;
439
440 sendAddr.sin_family = AF_INET;
441 sendAddr.sin_port = htons(rsSettings.GetPort());
442 sendAddr.sin_addr.s_addr = routerIP;
443
444 ssize_t res = sendto(sock, buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr *>(&sendAddr), sizeof(sendAddr));
445
446 if (res < 0)
447     logger("sendto error: %s", strerror(errno));
448
449 return (res != sizeof(buffer));
450 }
451 //-----------------------------------------------------------------------------
452 bool REMOTE_SCRIPT::GetUsers()
453 {
454 UserPtr u;
455
456 int h = users->OpenSearch();
457 assert(h && "USERS::OpenSearch is always correct");
458
459 while (users->SearchNext(h, &u) != 0)
460     SetUserNotifiers(u);
461
462 users->CloseSearch(h);
463 return false;
464 }
465 //-----------------------------------------------------------------------------
466 std::vector<uint32_t> REMOTE_SCRIPT::IP2Routers(uint32_t ip)
467 {
468 std::lock_guard lock(m_mutex);
469 for (auto& nr : netRouters)
470     if ((ip & nr.subnetMask) == (nr.subnetIP & nr.subnetMask))
471         return nr.routers;
472 return {};
473 }
474 //-----------------------------------------------------------------------------
475 void REMOTE_SCRIPT::SetUserNotifiers(UserPtr u)
476 {
477 ipNotifierList.push_front(RS::IP_NOTIFIER(*this, u));
478 connNotifierList.push_front(RS::CONNECTED_NOTIFIER(*this, u));
479 }
480 //-----------------------------------------------------------------------------
481 void REMOTE_SCRIPT::UnSetUserNotifiers(UserPtr u)
482 {
483 ipNotifierList.erase(std::remove_if(ipNotifierList.begin(),
484                                     ipNotifierList.end(),
485                                     USER_IS<IP_NOTIFIER>(u)),
486                      ipNotifierList.end());
487 connNotifierList.erase(std::remove_if(connNotifierList.begin(),
488                                       connNotifierList.end(),
489                                       USER_IS<CONNECTED_NOTIFIER>(u)),
490                        connNotifierList.end());
491
492 }
493 //-----------------------------------------------------------------------------
494 void REMOTE_SCRIPT::AddRSU(UserPtr user)
495 {
496 RS::USER rsu(IP2Routers(user->GetCurrIP()), user);
497 Send(rsu);
498
499 std::lock_guard lock(m_mutex);
500 authorizedUsers.insert(std::make_pair(user->GetCurrIP(), rsu));
501 }
502 //-----------------------------------------------------------------------------
503 void REMOTE_SCRIPT::DelRSU(UserPtr user)
504 {
505 std::lock_guard lock(m_mutex);
506 auto it = authorizedUsers.begin();
507 while (it != authorizedUsers.end())
508     {
509     if (it->second.user == user)
510         {
511         Send(it->second, true);
512         authorizedUsers.erase(it);
513         return;
514         }
515     ++it;
516     }
517 /*const auto it = authorizedUsers.find(user->GetCurrIP());
518 if (it != authorizedUsers.end())
519     {
520     Send(it->second, true);
521     authorizedUsers.erase(it);
522     }*/
523 }
524 //-----------------------------------------------------------------------------
525 void RS::IP_NOTIFIER::Notify(const uint32_t & /*oldValue*/, const uint32_t & newValue)
526 {
527 if (newValue != 0)
528     rs.AddRSU(user);
529 else
530     rs.DelRSU(user);
531 }
532 //-----------------------------------------------------------------------------
533 void RS::CONNECTED_NOTIFIER::Notify(const bool & /*oldValue*/, const bool & newValue)
534 {
535 if (newValue)
536     rs.AddRSU(user);
537 else
538     rs.DelRSU(user);
539 }
540 //-----------------------------------------------------------------------------
541 void REMOTE_SCRIPT::InitEncrypt(const std::string & password) const
542 {
543 unsigned char keyL[PASSWD_LEN];  // Пароль для шифровки
544 memset(keyL, 0, PASSWD_LEN);
545 strncpy(reinterpret_cast<char*>(keyL), password.c_str(), PASSWD_LEN);
546 Blowfish_Init(&ctx, keyL, PASSWD_LEN);
547 }
548 //-----------------------------------------------------------------------------
549 void REMOTE_SCRIPT::Encrypt(void * dst, const void * src, size_t len8) const
550 {
551 if (dst != src)
552     memcpy(dst, src, len8 * 8);
553 for (size_t i = 0; i < len8; ++i)
554     Blowfish_Encrypt(&ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
555 }
556 //-----------------------------------------------------------------------------