crawlserv++  [under development]
Application for crawling and analyzing textual content of websites.
TorControl.hpp
Go to the documentation of this file.
1 /*
2  *
3  * ---
4  *
5  * Copyright (C) 2020 Anselm Schmidt (ans[ät]ohai.su)
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version in addition to the terms of any
11  * licences already herein identified.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  *
21  * ---
22  *
23  * TorControl.hpp
24  *
25  * Connecting to the TOR control server/port to request a new identity.
26  *
27  * Created on: Nov 13, 2019
28  * Author: ans
29  */
30 
31 #ifndef NETWORK_TORCONTROL_HPP_
32 #define NETWORK_TORCONTROL_HPP_
33 
34 #include "Config.hpp"
35 
36 #include "../Main/Exception.hpp"
37 #include "../Timer/Simple.hpp"
38 
39 #include "asio.hpp"
40 
41 #include <array> // std::array
42 #include <cstdint> // std::uint16_t, std::uint64_t
43 #include <iostream> // std::cerr, std::endl
44 #include <string> // std::string, std::to_string
45 #include <string_view> // std::string_view
46 
47 namespace crawlservpp::Network {
48 
49  /*
50  * CONSTANTS
51  */
52 
55 
57  inline constexpr auto responseCodeLength{3};
58 
60  inline constexpr auto millisecondsPerSecond{1000};
61 
63 
64  /*
65  * DECLARATION
66  */
67 
69 
81  class TorControl {
82  public:
85 
86  TorControl(
87  std::string_view controlServer,
88  std::uint16_t controlPort,
89  std::string_view controlPassword
90  );
91  virtual ~TorControl();
92 
96 
97  [[nodiscard]] bool active() const noexcept;
98 
102 
103  void setNewIdentityMin(std::uint64_t seconds);
104  void setNewIdentityMax(std::uint64_t seconds);
105 
109 
110  bool newIdentity();
111 
115 
116  void tick();
117 
119 
121 
130 
134 
137  TorControl(TorControl&) = delete;
138 
140  TorControl& operator=(TorControl&) = delete;
141 
143  TorControl(TorControl&&) = delete;
144 
146  TorControl& operator=(TorControl&&) = delete;
147 
149 
150  private:
151  // settings
152  const bool isActive{false};
153  const std::string server;
154  const std::uint16_t port{};
155  const std::string password;
156  std::uint64_t newIdentityNotBefore{};
157  std::uint64_t newIdentityAfter{};
158 
159  // asio context and socket
160  asio::io_context context;
161  asio::ip::tcp::socket socket;
162 
163  // identity time and timers
164  Timer::Simple minTimer;
165  Timer::Simple maxTimer;
166  std::uint64_t elapsedMin{};
167  std::uint64_t elapsedMax{};
168  };
169 
170  /*
171  * IMPLEMENTATION
172  */
173 
175 
187  std::string_view controlServer,
188  std::uint16_t controlPort,
189  std::string_view controlPassword
190  ) : isActive(!controlServer.empty()),
191  server(controlServer),
192  port(controlPort),
193  password(controlPassword),
194  socket(this->context) {}
195 
197 
201  if(this->socket.is_open()) {
202  asio::error_code error;
203 
204  this->socket.shutdown(asio::ip::tcp::socket::shutdown_both, error);
205 
206  if(error) {
207  std::cerr << "TorControl::~TorControl(): "
208  << error.message()
209  << std::endl;
210  }
211  }
212  }
213 
215 
219  inline bool TorControl::active() const noexcept {
220  return this->isActive;
221  }
222 
224 
233  inline void TorControl::setNewIdentityMin(std::uint64_t seconds) {
234  this->newIdentityNotBefore = seconds;
235 
236  // reset timer
237  this->elapsedMin = 0;
238 
239  this->minTimer.tick();
240  }
241 
243 
250  inline void TorControl::setNewIdentityMax(std::uint64_t seconds) {
251  this->newIdentityAfter = seconds;
252 
253  // reset timer
254  this->elapsedMax = 0;
255 
256  this->maxTimer.tick();
257  }
258 
260 
274  inline bool TorControl::newIdentity() {
275  // check whether a TOR control server/port has been set
276  if(!(this->isActive)) {
277  throw Exception("No TOR control server/port set");
278  }
279 
280  // check whether a sufficient amount of time has passed since the last request
281  if(this->newIdentityNotBefore > 0) {
282  this->elapsedMin += this->minTimer.tick();
283 
284  if(this->elapsedMin / millisecondsPerSecond < this->newIdentityNotBefore) {
285  return false;
286  }
287 
288  this->elapsedMin = 0;
289  }
290 
291  // create asio resolver
292  asio::ip::tcp::resolver resolver(this->context);
293 
294  try {
295  // resolve the address of the control server
296  asio::ip::tcp::resolver::results_type endpoints{
297  resolver.resolve(
298  this->server,
299  std::to_string(this->port),
300  asio::ip::tcp::resolver::numeric_service
301  )
302  };
303 
304  // connect to control server
305  asio::connect(this->socket, endpoints);
306 
307  // send authentification
308  const std::string auth("AUTHENTICATE \"" + this->password + "\"\n");
309 
310  asio::write(this->socket, asio::buffer(auth.data(), auth.size()));
311 
312  // read response code (response should be "250 OK" or "515 Bad authentication")
313  std::array<char, responseCodeLength> response{};
314 
315  this->socket.read_some(asio::mutable_buffer(response.data(), responseCodeLength));
316 
317  // check response code
318  if(response[0] != '2' || response[1] != '5' || response[2] != '0') {
319  throw Exception("Authentification failed");
320  }
321 
322  // send command to request a new identity
323  const std::string command("SIGNAL NEWNYM\r\n");
324 
325  asio::write(this->socket, asio::buffer(command.data(), command.size()));
326 
327  // reset timer if necessary
328  if(this->newIdentityAfter > 0) {
329  this->elapsedMax = 0;
330 
331  this->maxTimer.tick();
332  }
333  }
334  catch(const asio::system_error& e) {
335  throw Exception(e.what());
336  }
337 
338  return true;
339  }
340 
342 
346  inline void TorControl::tick() {
347  // check whether timer is enabled
348  if(this->isActive && this->newIdentityAfter > 0) {
349  // get elapsed time (in ms)
350  this->elapsedMin += this->minTimer.tick();
351  this->elapsedMax += this->maxTimer.tick();
352 
353  // check elapsed time (in s)
354  if(this->elapsedMax / millisecondsPerSecond > this->newIdentityAfter) {
355  // request new identity
356  this->newIdentity();
357 
358  // reset timer
359  this->elapsedMax = 0;
360 
361  this->maxTimer.tick();
362  }
363  }
364  }
365 
366 } /* namespace crawlservpp::Network */
367 
368 #endif /* NETWORK_TORCONTROL_HPP_ */
Class for TOR control exceptions.
Definition: TorControl.hpp:129
TorControl & operator=(TorControl &)=delete
Deleted copy assignment operator.
#define MAIN_EXCEPTION_CLASS()
Macro used to easily define classes for general exceptions.
Definition: Exception.hpp:50
TorControl(std::string_view controlServer, std::uint16_t controlPort, std::string_view controlPassword)
Constructor creating context and socket for the connection to the TOR control server/port.
Definition: TorControl.hpp:186
bool newIdentity()
Requests a new TOR identity via the set TOR control server/port.
Definition: TorControl.hpp:274
void setNewIdentityMax(std::uint64_t seconds)
Sets the time (in seconds) after which to automatically request a new TOR identity.
Definition: TorControl.hpp:250
constexpr auto millisecondsPerSecond
The number of milliseconds per second.
Definition: TorControl.hpp:60
A simple timer.
Definition: Simple.hpp:53
Controls a TOR service via a TOR control server/port, if available.
Definition: TorControl.hpp:81
void tick()
Checks whether to request a new TOR identity.
Definition: TorControl.hpp:346
void setNewIdentityMin(std::uint64_t seconds)
Sets the time (in seconds) in which to ignore requests for a new identity.
Definition: TorControl.hpp:233
void write(const std::string &fileName, const std::string &content, bool binary)
Writes the given content to the given file.
Definition: File.hpp:137
std::uint64_t tick()
Timer tick returning the number of milliseconds passed.
Definition: Simple.hpp:98
bool active() const noexcept
Gets whether a TOR control server/port is set.
Definition: TorControl.hpp:219
constexpr auto responseCodeLength
The length of a HTTP response code.
Definition: TorControl.hpp:57
Namespace for networking classes.
Definition: Config.hpp:45
virtual ~TorControl()
Destructor shutting down remaining connections to the TOR control server/port if necessary.
Definition: TorControl.hpp:200