├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── NEWS.md ├── README.md ├── include ├── BriandDefines.hxx ├── BriandNet.hxx ├── BriandTorAes.hxx ├── BriandTorCell.hxx ├── BriandTorCertificates.hxx ├── BriandTorCircuit.hxx ├── BriandTorCircuitsManager.hxx ├── BriandTorCryptoUtils.hxx ├── BriandTorDefinitions.hxx ├── BriandTorDirAuthority.hxx ├── BriandTorEsp32Config.hxx ├── BriandTorRelay.hxx ├── BriandTorRelaySearcher.hxx ├── BriandTorSocks5Proxy.hxx ├── BriandTorStatistics.hxx ├── BriandUtils.hxx └── README ├── lib └── README ├── partitions.csv ├── platformio.ini ├── sdkconfig.esp-wrover-kit ├── sdkconfig.esp32-s2-saola-1 ├── sdkconfig.lolin_d32 ├── src ├── BriandEspLogging.cpp ├── BriandNet.cpp ├── BriandTorCell.cpp ├── BriandTorCertificates.cpp ├── BriandTorCircuit.cpp ├── BriandTorCircuitsManager.cpp ├── BriandTorCryptoUtils.cpp ├── BriandTorDirAuthority.cpp ├── BriandTorRelay.cpp ├── BriandTorRelaySearcher.cpp ├── BriandTorSocks5Proxy.cpp ├── BriandTorStatistics.cpp ├── BriandUtils.cpp ├── CMakeLists.txt └── main.cpp └── test └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | .vscode/*.log 7 | data 8 | GitHowTo.txt 9 | IDFHowTo.txt 10 | OLDmain.old 11 | DEBUG_JTAG.txt 12 | main_linux_exe 13 | sdkconfig.*.old 14 | sdkconfig.*.bak 15 | sdkconfig.*.backup 16 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "iostream": "cpp", 4 | "iosfwd": "cpp", 5 | "string": "cpp", 6 | "string_view": "cpp", 7 | "array": "cpp", 8 | "*.tcc": "cpp", 9 | "memory": "cpp", 10 | "future": "cpp", 11 | "istream": "cpp", 12 | "functional": "cpp", 13 | "tuple": "cpp", 14 | "utility": "cpp", 15 | "atomic": "cpp", 16 | "cctype": "cpp", 17 | "chrono": "cpp", 18 | "clocale": "cpp", 19 | "cmath": "cpp", 20 | "codecvt": "cpp", 21 | "condition_variable": "cpp", 22 | "csignal": "cpp", 23 | "cstdarg": "cpp", 24 | "cstddef": "cpp", 25 | "cstdint": "cpp", 26 | "cstdio": "cpp", 27 | "cstdlib": "cpp", 28 | "cstring": "cpp", 29 | "ctime": "cpp", 30 | "cwchar": "cpp", 31 | "cwctype": "cpp", 32 | "deque": "cpp", 33 | "list": "cpp", 34 | "unordered_map": "cpp", 35 | "vector": "cpp", 36 | "exception": "cpp", 37 | "algorithm": "cpp", 38 | "iterator": "cpp", 39 | "map": "cpp", 40 | "memory_resource": "cpp", 41 | "numeric": "cpp", 42 | "optional": "cpp", 43 | "random": "cpp", 44 | "ratio": "cpp", 45 | "set": "cpp", 46 | "system_error": "cpp", 47 | "type_traits": "cpp", 48 | "fstream": "cpp", 49 | "initializer_list": "cpp", 50 | "iomanip": "cpp", 51 | "limits": "cpp", 52 | "mutex": "cpp", 53 | "new": "cpp", 54 | "ostream": "cpp", 55 | "sstream": "cpp", 56 | "stdexcept": "cpp", 57 | "streambuf": "cpp", 58 | "thread": "cpp", 59 | "cinttypes": "cpp", 60 | "typeinfo": "cpp", 61 | "*.ipp": "cpp" 62 | } 63 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.0) 2 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 3 | project(toresp32) 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Variables to control Makefile operation 2 | # This files operates smoothly on Platformio project 3 | # Compile with bash make command in the project base directory. 4 | 5 | # Min. 8.4.0 6 | MIN_GCC_VERSION = "8.4" 7 | # Path to src/ directory 8 | SRCPATH = src 9 | # Path to include/ directory 10 | INCLUDEPATH = include 11 | # Path to cJSON component path (IDF Framework or git clone) 12 | # (NO MORE NEEDED) CJSON_PATH = $(IDF_PATH)/components/json/cJSON 13 | # Base Path to LibBriandIDF (with standard platformio.ini should be this path) 14 | BRIAND_LIB_PATH = .pio/libdeps/lolin_d32/LibBriandIDF 15 | # Output executable name 16 | OUTNAME = main_linux_exe 17 | # Compiler g++ 18 | CXX = g++ 19 | # Flags required 20 | CXXFLAGS = -g -pthread -lmbedtls -lmbedcrypto -lmbedx509 -lsodium -std=gnu++17 21 | 22 | #Target main 23 | main: 24 | $(CXX) $(CXXFLAGS) -o $(OUTNAME) $(SRCPATH)/*.cpp $(BRIAND_LIB_PATH)/src/*.cpp -I$(INCLUDEPATH) -I$(BRIAND_LIB_PATH)/include 25 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # Development status 2 | 3 | ## Next steps 4 | 5 | * Place BriandError management on strategic points for debugging 6 | * Consider to package as PlatformIO library 7 | * Consider to build on-demand circuits for specific requested ports: 8 | * requires cache to save allowed ports 9 | * requires GetExitNode method introducing unsigned short port parameter to find suitable exit with specific port if provided 10 | * requires parameter modification of BuildCircuit introducing unsigned short port parameter 11 | * requires BuildCircuit method to check if port specified and choose a suitable exit node before all 12 | * requires CircuitManager to check for suitable circuits and build one if none capable (destroying the oldest?) 13 | * Implement a vector of nodes. 14 | * Authenticate cell? => Prepare stub method to authenticate client 15 | 16 | ## 17 | 18 | * New configurable queue limit settings. 19 | * Investigate on protocol errors: seems same exit node in multiple circuit causing some trouble. However protocol error always comes from middle :/ 20 | 21 | Seems to be, persistent errors are (sample log): 22 | 23 | ``` 24 | W briandstream [ERR][BADB4A3C] TorStream error, received unexpected cell from middle node: RELAY_TRUNCATED 25 | W briandstream [WARN][BADB4A3C] TorStreamRead received RELAY_TRUNCATE / RELAY_TRUNCATED, reason = PROTOCOL. StreamID is 0002, Stream Window is 495, Circ Window is 945 26 | W briandstream [ERR][BADB4A3C] TorStream error, received unexpected cell from middle node: RELAY_TRUNCATED 27 | W briandstream [WARN][BADB4A3C] TorStreamRead received RELAY_TRUNCATE / RELAY_TRUNCATED, reason = PROTOCOL. StreamID is 0002, Stream Window is 495, Circ Window is 945 28 | W briandstream [ERR][CE2F3678] TorStream error, received unexpected cell from middle node: RELAY_TRUNCATED 29 | W briandstream [WARN][CE2F3678] TorStreamSingle received RELAY_TRUNCATE / RELAY_TRUNCATED, reason = PROTOCOL. 30 | W briandstream [WARN][CE2F3678] TorStreamStart error: cannot connect to required destination. 31 | W briandstream [ERR][94CE6B63] TorStream error, received unexpected cell from middle node: RELAY_TRUNCATED 32 | W briandstream [WARN][94CE6B63] TorStreamRead received RELAY_TRUNCATE / RELAY_TRUNCATED, reason = PROTOCOL. StreamID is 0002, Stream Window is 500, Circ Window is 1000 33 | W briandstream [ERR][86F4E31A] TorStream error, received unexpected cell from middle node: RELAY_TRUNCATED 34 | W briandstream [WARN][86F4E31A] TorStreamRead received RELAY_TRUNCATE / RELAY_TRUNCATED, reason = PROTOCOL. StreamID is 0004, Stream Window is 498, Circ Window is 998 35 | ``` 36 | 37 | May be due to un-real window resizing exactly at 450 (stream) / 900 (circuit). Should do a dedicated task or trigger before this limit... no 38 | 39 | **SOLVED** in RELAY_SENDME the last sent (by *my* side digest is required). 40 | 41 | * Mbedtls on linux platform with similar settings like ESP. However sometimes very slow on read operations. Should investigate. 42 | * Using unique_lock for thread-safety. Should solve all invalid-read-size errors shown in valgrind (now too many concurrent pthreads!). Threads that may share circuit object are: CircuitsManager, Proxy Async Reader, Proxy Async Writer. 43 | * TorStreamRead() method needs to be changed, otherwise could read only padding and lock the circuit without any data to write back! Added an "ignorableRead" parameter in order to unlock the circuit and let the other threads do any work. (Otherwise infinite lock beacause infinite loop when only paddings are available!) **Working well!** 44 | * Added a proxy client request queue in order to not close the socket proxy-side so the connection will be hold (ex. firefox loading images connection close = no image) 45 | * Testing on ESP32 : some pthreads not created, added check 46 | * Added LAST_COMMAND with UP/DOWN arrows support (only Putty and escape-allowed terminals) 47 | * Now ntor-key downloaded previously and saved in the cache (less long fetch descriptors calls each time for the same selected node) 48 | * Added authority directory optimization for faster downloads 49 | 50 | ## 2021-08-21 51 | 52 | * Possible bug in tor relay searcher: too much rebuild cache requests... SOLVED! 53 | * Separate circuit log from stream log to debug better 54 | * Socks5 Proxy better task management (simplified, using also make_shared to avoid invalid reads) 55 | * Started to use error codes 56 | * Possible bug in stream: after some cells exchanged, seems unrecognize all. Maybe due to the additional bytes download? No.. found due to "old" stream cells still to be received by the node! How should treat? Roll the backward digest or not? 57 | * Testing std::async / future for Stream read/write because void* parameter of xTaskCreate is very limiting 58 | * A test on ESP32 shows interesting results: **pthreads stack requirement is less than FreeRTOS ones**. With the same function contents an std::async thread (std::lauch async) shows 1168 min.free thread stack, a std::thread show 1592 min.free stack, xTaskCreate shows 668. Thinking to switch all to pthreads (and so avoid the annoying void* parameter). Other test shows that returning pthreads have no problems and are killed by FreeRTOS automatically. Sample code used: 59 | 60 | ```C++ 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | 73 | using namespace std; 74 | 75 | extern "C" { 76 | void app_main(); 77 | } 78 | 79 | class BigObj { 80 | public: 81 | static const size_t size = 1024; 82 | unsigned char buffer[size]; 83 | }; 84 | 85 | void func(void* z) { 86 | while (1) { 87 | BigObj a; 88 | auto b = make_unique(); 89 | bzero(a.buffer, a.size); 90 | for (int i =0; isize; i++) b->buffer[i] = 0xAA; 92 | vTaskDelay(500 / portTICK_PERIOD_MS); 93 | } 94 | } 95 | 96 | void rfunc1(void* z) { 97 | for(int j=0; j<15; j++) { 98 | BigObj a; 99 | auto b = make_unique(); 100 | bzero(a.buffer, a.size); 101 | for (int i =0; isize; i++) b->buffer[i] = 0xAA; 103 | printf("*** I AM THREAD 1\n"); 104 | vTaskDelay(500 / portTICK_PERIOD_MS); 105 | } 106 | } 107 | 108 | void rfunc2(void* z) { 109 | for(int j=0; j<15; j++) { 110 | BigObj a; 111 | auto b = make_unique(); 112 | bzero(a.buffer, a.size); 113 | for (int i =0; isize; i++) b->buffer[i] = 0xAA; 115 | printf("*** I AM THREAD 2\n"); 116 | vTaskDelay(500 / portTICK_PERIOD_MS); 117 | } 118 | } 119 | 120 | void callThreads() { 121 | xTaskCreate(func, "T_MANUAL1", 2048, NULL, 5, NULL); 122 | 123 | esp_pthread_cfg_t cfg; 124 | cfg = esp_pthread_get_default_config(); 125 | 126 | cfg.thread_name = "PT_STD1"; 127 | esp_pthread_set_cfg(&cfg); 128 | std::thread t1(func, (void*)NULL); 129 | t1.detach(); 130 | 131 | cfg.thread_name = "PT_STD2"; 132 | esp_pthread_set_cfg(&cfg); 133 | std::thread t2(rfunc2, (void*)NULL); 134 | t2.detach(); 135 | 136 | cfg.thread_name = "PT_ASYNC"; 137 | esp_pthread_set_cfg(&cfg); 138 | auto ft = std::async(std::launch::async, rfunc1, (void*)NULL); 139 | } 140 | 141 | void app_main() { 142 | 143 | printf("[INFO] Initializing NVS..."); 144 | auto ret = nvs_flash_init(); 145 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 146 | ESP_ERROR_CHECK(nvs_flash_erase()); 147 | ret = nvs_flash_init(); 148 | } 149 | ESP_ERROR_CHECK(ret); 150 | printf("done.\n"); 151 | 152 | // De-buffered serial communication 153 | printf("[INFO] Unbuffering stdout..."); 154 | setvbuf(stdout, NULL, _IONBF, 0); 155 | printf("done.\n"); 156 | printf("[INFO] Unbuffering stdin..."); 157 | setvbuf(stdin, NULL, _IONBF, 0); 158 | printf("done.\n"); 159 | 160 | callThreads(); 161 | 162 | while(1) { 163 | TaskStatus_t arr[15]; 164 | uint32_t tr; 165 | 166 | auto ss = uxTaskGetSystemState(arr, 15, &tr); 167 | printf("Task\t\tMIN STACK\n"); 168 | for (size_t i=0; i Wi-Fi -> Max Number of Wifi static TX buffers = 32* 212 | * *Component config -> Wi-Fi -> Max number of WiFi cache TX buffers = 32* 213 | * Added more statistics, compare with Linux porting. 214 | * Added suppress-log 215 | * Added random-skip lines to consensus download and file flushing 216 | * Removed parameter *Component config -> FreeRTOS -> ENABLED Place FreeRTOS functions into Flash* I think causing cache failures and frequent download. 217 | * Better cache access with waiting search requests 218 | * Better stack sizes when log suppressed 219 | * Possible bug in tor relay searcher: too much rebuild cache requests... 220 | 221 | ## 2021-08-18 222 | 223 | * Solved the BIIIIIIIG bug in the while() that was causing heap paaaaaaaain :/ left the set parameters in previous news. Reset the previously commented "// reserve some bytes" 224 | 225 | * Start-up free heap ~285KB (now moved BEFORE CircuitsManager startup) 226 | * With 5 built circuits, not connected to, AP, no proxy used: HEAP FREE: 124628 / 369256 bytes. MAX FREE 213564 MIN FREE 124072 LARGEST FREE BLOCK: 65536 227 | * With 5 circuits built, connected to AP, no proxy used: HEAP FREE: 121316 / 369256 bytes. MAX FREE 213564 MIN FREE 119620 LARGEST FREE BLOCK: 65536 228 | * With 5 circuits built, connected to AP, proxy after use with curl: HEAP FREE: 103508 / 369256 bytes. MAX FREE 213564 MIN FREE 101624 LARGEST FREE BLOCK: 65536 229 | * With 5 circuits built, connected to AP, proxy after use with firefox: HEAP FREE: 230 | 231 | * Swtiched now to 6 circuits (reset the QUEUE length to 100% causes crash but parameters were fine) 232 | * New loglevel command for any tag, "log TAG N/E/", each object has its own now in order to limit output. 233 | * Removed previous byte reservations for vector<> and changed back to dynamic buffers and structs. 234 | * Testing with 8 circuits and cache increased to 255 nodes (~60KB files), but needed to change Wi-Fi dynamic buffers to 64 to avoid AP disconnections (with 40 disconnects when using proxy) 235 | 236 | * Start-up free heap still ~285KB 237 | * With 8 built circuits, not connected to, AP, no proxy used: HEAP FREE: 89708 / 368696 bytes. MAX FREE 213128 MIN FREE 83076 LARGEST FREE BLOCK: 65536 238 | * With 8 circuits built, connected to AP, no proxy used: HEAP FREE: 67584 / 368696 bytes. MAX FREE 213128 MIN FREE 62532 LARGEST FREE BLOCK: 16384 239 | * With 8 circuits built, connected to AP, proxy after use with curl: HEAP FREE: 108384 / 368696 bytes. MAX FREE 213128 MIN FREE 62532 LARGEST FREE BLOCK: 65536 240 | * With 8 circuits built, connected to AP, proxy after use with firefox: HEAP FREE: 87740 / 368696 bytes. MAX FREE 213128 MIN FREE 42680 LARGEST FREE BLOCK: 32768 241 | * New cache size of 255 nodes does not increase so much spiffs usage and makes things more reliable in relay searching 242 | * Added settings TOR_MUST_HAVE_PORTS in order to select only the exit nodes that accepts connections to the listed ports. This leds to download full consensus! 243 | * Added command to change proxy port 244 | * Removed all old Onionoo commented implementations 245 | * Reset cache size to 100 nodes, too much time required when exit port filtering is needed! 246 | * No. of max open sockets setting promoted to 16. 247 | 248 | ## 2021-08-17 249 | 250 | * Working to new release 1.1.0 with faster proxy 251 | * Moved to 5 maximum open circuits (need more memory, AP connections troubles), should also be enough for new proxy handlers with async read/write operations. 252 | * Removed led blinking (just off always if parameter set, or ON when circuits ready) 253 | * New proxy requires a higher timeout, set TOR_SOCKS5_PROXY_TIMEOUT_S to 30 seconds. 254 | * New proxy AWESOME: from 40seconds to 13seconds on the testing web page! 255 | * removed DELETED methods and old stuff 256 | * Redefined task priorities, and set the following settings in order to avoid connection errors to AP (found on https://github.com/espressif/esp-idf/issues/2915): 257 | 258 | *Component config -> Wi-Fi -> DISABLED WiFi AMPDU TX* 259 | 260 | *Component config -> Wi-Fi -> DISABLED WiFi AMPDU RX* 261 | 262 | * Need to track *heap_caps_get_largest_free_block()* crashes are probably due to heap fragmentation! 263 | * Moved ResetCertificates() after the CREATE2 to save RAM before Extending. 264 | * Noted that if Firefox has proxy info, a fresh restarted ESP when connected to AP will be annoied by a lot of requests and crashes for out of memory! 265 | This is due to heap fragmentation, there are still ~12KB minimum of free heap but they could be fragmented (noted malloc() failed exceptions). 266 | To solve issue, following settings have been changed and the maximum dimension for listen() on proxy is HALF of the available circuits. Settings have been 267 | changed by reading [lwIP minimum ram](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html) and [WiFi memory optimization](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wifi-buffer-usage) documentations. For Wi-Fi buffer the Default configuration has been used. However some parameters were diffferent and found AP connection issues, so follows full parameters list. 268 | 269 | Also the TorProxy on client accept/read/write operation needed modifications: static buffers where possible, increased operation delay to 300ms. Vectors there have been pre-allocated using a reserve() called with the maximum needed. This technique has been used also elsewhere (find it by searching "// reserve some bytes" comment in code). 270 | 271 | Results after this operation: 272 | 273 | * RAM: [= ] 11.1% (used 36472 bytes from 327680 bytes) 274 | * Flash: [====== ] 62.1% (used 1301493 bytes from 2097152 bytes) 275 | * Start-up free heap ~300KB (now moved BEFORE CircuitsManager startup) 276 | * With 5 built circuits, not connected to, AP, no proxy used: HEAP FREE: 116616 / 369256 bytes. MAX FREE 213564 MIN FREE 114456 LARGEST FREE BLOCK: 65536 277 | * With 5 circuits built, connected to AP, no proxy used: HEAP FREE: 123300 / 369496 bytes. MAX FREE 230236 MIN FREE 120792 LARGEST FREE BLOCK: 65536 278 | * With 5 circuits built, connected to AP, proxy in use with curl: HEAP FREE: 99700 / 369256 bytes. MAX FREE 213612 MIN FREE 86808 LARGEST FREE BLOCK: 65536 279 | * With 5 circuits built, connected to AP, proxy in use with firefox: MIN free = , MAX free = , LARGEST FREE BLOCK = 280 | 281 | **DISABLED PSRAM as ESP32 in version LolinD32 has not. Could be enabled when WRover used. Backup of old file sdkconfig.lolin_d32.backup and done a fresh Menuconfig** 282 | 283 | *TESTING WITH NORMAL CPU SPEED 160 vs 240 to check if crashes are related to this* 284 | 285 | *Component config -> Wi-Fi -> Max Number of Wifi static RX buffers = 16 (16 fine with 6 circuits keep-alive)* 286 | 287 | *Component config -> Wi-Fi -> Max Number of Wifi dynamic RX buffers = 32 (32 fine with 6 circuits keep-alive)* 288 | 289 | *Component config -> Wi-Fi -> Type of WiFi TX buffers = Dynamic (Static) //this setting could not be changed from Static if PSRAM enabled* 290 | 291 | *Component config -> Wi-Fi -> Max Number of Wifi dynamic/static TX buffers = 32 (32 fine with 6 circuits keep-alive)* 292 | 293 | *Component config -> Wi-Fi -> DISABLED WiFi AMPDU TX // for connet-to-ap issues* 294 | 295 | *Component config -> Wi-Fi -> DISABLED WiFi AMPDU RX // for connet-to-ap issues* 296 | 297 | *Component config -> Wi-Fi -> DISABLED WiFi RX IRAM speed optimization* 298 | 299 | *Component config -> Wi-Fi -> DISABLED WiFi IRAM speed optimization* 300 | 301 | *Component config -> Wi-Fi -> left ENABLED WPA-3-Personal* 302 | 303 | *Component config -> LWIP -> ICMP -> ENABLED answer to pings (useful for debugging)* 304 | 305 | *Component config -> LWIP -> DISABLED LWIP IRAM optimization* 306 | 307 | *Component config -> LWIP -> Max Number of open sockets = 12* 308 | 309 | *Component config -> LWIP -> TCPIP task receive mail box size = 32* 310 | 311 | *Component config -> LWIP -> IPV6 left enabled, could save a lot (~7KB RAM) but one day I will implement IPv6* 312 | 313 | *Component config -> LWIP -> TCP -> Maximum active TCP Connections = 16* 314 | 315 | *Component config -> LWIP -> TCP -> Maximum listening TCP Connections = 16* 316 | 317 | *Component config -> LWIP -> TCP -> Maximum segment size (MSS) = 1024 (default was 1440)* 318 | 319 | *Component config -> LWIP -> TCP -> Default send buffer size = 2440 (>2xMSS as required, default was 5770)* 320 | 321 | *Component config -> LWIP -> TCP -> Default receive window size = 2440 (>2xMSS as required, default was 5770)* 322 | 323 | *Component config -> LWIP -> TCP -> Default TCP receive mail box size = 6 (default was 6)* 324 | 325 | *Component config -> LWIP -> ICMP -> ENABLED answer to pings (useful)* 326 | 327 | *Component config -> LWIP -> ENABLED Enable reassembly incoming fragmented IP4 packets (due to small fragments, assert() fails sometimes)* 328 | 329 | *Component config -> LWIP -> ENABLED Enable reassembly incoming fragmented IP6 packets (due to small fragments, assert() fails sometimes)* 330 | 331 | *Component config -> LWIP -> DISABLED Enable LWIP ASSERT checks (could cause crashes)* 332 | 333 | *Component config -> LWIP -> ICMP -> ENABLED answer to pings (useful)* 334 | 335 | *Component config -> LWIP -> TEMPORARY ENABLED SOME SETTINGS in Enable LWIP Debug (useful)* 336 | 337 | *Component config -> Wi-Fi Provisioning manager -> Max Wi-Fi Scan result entries = 6* 338 | 339 | *Component config -> FreeRTOS -> FreeRTOS assertions -> Print and continue (useful for debugging)* 340 | 341 | *Component config -> mbedTLS -> TLS maximum incoming fragment length = 4096 (default was 16384)* 342 | 343 | *Component config -> mbedTLS -> TLS maximum outgoing fragment length = 2048 (default was 4096)* 344 | 345 | * Removed old sdkconfig files to avoid misunderstandings 346 | * Added a REQUEST_QUEUE to limit to 2/3 of the alive circuits the Proxy requests (otherwise a lack of memory and crash could happen) 347 | * Lowered some stack sizes for tasks, however need to test in DEBUG mode because of more stack required with printf's 348 | * Removed shutdown() for sockets as it is causing fatal error on LWIP TCP/IP stack (see https://github.com/espressif/esp-idf/issues/2931). 349 | 350 | ## 2021-08-15 351 | 352 | * Added task monitoring command and enabled config parameter USE_TRACE_FACILITY 353 | * Testing task stack usage on ESP system: done optimizations 354 | * Testing STA auto disconnect cause: found powersave (now set to off by default) and this error: 355 | 356 | *I (919907) wifi:bcn_timout,ap_probe_send_start* 357 | 358 | *I (923657) wifi:ap_probe_send over, resett wifi status to disassoc* 359 | 360 | solved by changing staCheckHealth() with just a simple *esp_wifi_connect()* call on auto-reconnect code. 361 | * Optimized mbedTLS library memory usage by setting following options as ENABLED in menuconfig: 362 | 363 | *Component config -> mbedTLS -> Using dynamic TX/RX buffer* 364 | 365 | *Component config -> mbedTLS -> Using dynamic TX/RX buffer -> Free SSL peer certificate after...* 366 | 367 | *Component config -> mbedTLS -> Using dynamic TX/RX buffer -> Free private key after...* 368 | 369 | *Component config -> mbedTLS -> Using dynamic TX/RX buffer -> Free private key after... -> Free SSL ca certificate after...* 370 | 371 | *Component config -> mbedTLS -> Using dynamic TX/RX buffer -> Free private key after...* 372 | 373 | BEFORE: each circuit requires ~30KB of heap (~4KB for object, ~26KB for mbedtls client communications). MIN FREE HEAP ~10KB 374 | 375 | AFTER: each circuit requires ~10KB of heap (~4KB for object, ~6KB for mbedtls client communications). MIN FREE HEAP ~80KB with 3 built circuits 376 | * Increased default no. of circuits (TOR_CIRCUITS_KEEPALIVE) to 8 (tested, no low memory and network works, otherwise sockets/ap connections seems not to work well) 377 | 378 | *Component config -> Wi-Fi -> Max Number of WiFi static RX/TX bufers = 16 (10 was default)* 379 | 380 | *Component config -> Wi-Fi -> WiFi AMPDU TX BA window size = 16 (6 was default)* 381 | 382 | *Component config -> Wi-Fi -> WiFi AMPDU RX BA window size = 16 (6 was default)* 383 | 384 | *Component config -> LWIP -> Max Number of open sockets = 16 (10 was default)* 385 | 386 | *Component config -> LWIP -> TCP -> Maximum active TCP Connections = 16 (10 was default)* 387 | 388 | *Component config -> LWIP -> TCP -> Maximum listening TCP Connections = 16 (10 was default)* 389 | 390 | *Component config -> LWIP -> TCP -> Maximum segment size (MSS) = 1440 (kept default)* 391 | 392 | *Component config -> LWIP -> TCP -> Default send buffer size = 2880 (2xMSS as required, default was 5770)* 393 | 394 | *Component config -> LWIP -> TCP -> Default receive window size = 2880 (2xMSS as required, default was 5770)* 395 | 396 | *Component config -> LWIP -> TCP -> Default TCP receive mail box size = 16 (default was 6)* 397 | * PROXY Authentication user/psw 398 | 399 | ## 2021-08-08 400 | 401 | * Need to change a little Socks5Proxy not catching client disconnect for http request and keeping socket opened. (main thread + one thread per accept()) 402 | * Removed COMMANDID and leak testing, switching to full socks5 proxy 403 | * Moving to another cache implementation using microdescriptors from Authorities 404 | * Added heap monitor to meminfo command 405 | * Moved to microdescriptor cache and more efficient FetchDescriptorsFromAuthorities with readLine method of LibBriandIDF 406 | * Added STA command for connect/disconnect and auto-reconnect 407 | * Something is eating all heap (found with 3 built circuits goes below 10.000bytes free) 408 | * Optimized use of vector->data() instead of copy to the "old" buffer style 409 | 410 | ## 2021-08-07 411 | 412 | * First streaming success! used curl in linux env: *curl http://ifconfig.me/all.json --socks5-hostname 127.0.0.1:5001* 413 | * Seems something is broken on the FetchDescriptors response (truncated at half), need debug. 414 | * Seems something wrong with bind() and listen() in socks5 need debug 415 | * Added ESP Exception decoder for command line *java -jar EspStackTraceDecoder.jar * 416 | * Last crashes are due to low memory (causing also STA reset...) with cache of 30 nodes and 2 working circuits seems stable 417 | * First streaming success also with CURL/ESP32! 418 | 419 | ## 2021-08-01 420 | 421 | * Debugging with linux porting and valgrind: resolved some bugs 422 | * Testing with valgrind 423 | * Found that torcache has too poor nodes and sometimes the same is chosen 424 | * Found that crashes are due to task calling objects that are "busy" and are destroyed before finishing. 425 | * Added circuit status flags 426 | * Better task scheduling resolved crashes (on linux, still to deep test on esp32), remains one related to blocking I/O on cache files 427 | * Solved wrong file on RelaySearcher 428 | 429 | ## 2021-07-31 430 | 431 | * Random crashes still persist (when restarting tor circuits manager task), need deep debugging 432 | * Finished SOCKS5 class 433 | * Changed public IP request to IPFY API 434 | * Arrived ESP-Prog debugging board, testing and debugging!! 435 | * Upgraded LibBriandIDF, working to linux porting for better debugging and tests. 436 | 437 | ## 2021-07-25 438 | 439 | * Random crashes still persist (when restarting tor circuits manager task), need deep debugging 440 | * Started to write SOCKS5 class 441 | * Changes to Stream methods, more simple and raw. 442 | 443 | ## 2021-07-18 444 | 445 | * IDF updated: Platformio update framework-espidf 3.40300.0 (4.3.0) 446 | * Changed logging system with ESP default 447 | * Tested Circuits Manager, working 448 | * Added test tor command and tested PADDING on built circuits, hostname resolution. All OK! 449 | * BUG: Sometimes tasks launch sys_check_timeouts errors, related to tcpip thread. Solution could be one task for all circuits with delayed building 450 | 451 | ## 2021-07-17 452 | 453 | * Bug solved on onionoo URL separator 454 | * Wrote Stream method 455 | * Wrote TorResolve method 456 | * Wrote Circuits Manager class 457 | 458 | ## 2021-05-29 459 | * EXTEND with exit now working!! The problem was AES not keeping IV/Nonce not updated and wrong backard digest calculation. 460 | * Found problem with digest update, resolved 461 | * Backward digest verification and update 462 | * Digesting function bug/misuse correction adding mbedtls right methods 463 | * Added method to verify relay cell before building fields 464 | 465 | ## 2021-05-22 466 | 467 | * EXTEND2 working, success on building the first hop! 468 | * Resolved EXTEND2 failures due to a mistake on fingerprint length 469 | 470 | ## 2021-05-15 471 | 472 | * Library upgrade and improvements 473 | * Re-testing CREATE2 failure 474 | * Solved CREATE2 (error due to mbedtls big-endian bytes instead of little-endian) 475 | * Added RELAY cell basic handling 476 | * Added last_working_directory auth as static 477 | * Updated NTOR handshake digest fields error 478 | 479 | ## 2021-05-08 480 | ## Switch to IDF complete 481 | RAM: [= ] 12.0% (used 39440 bytes from 327680 bytes) 482 | Flash: [====== ] 61.7% (used 1293890 bytes from 2097152 bytes) 483 | 484 | **SdkConfig changes**: 485 | 486 | Enabled Component config->HTTP Server->WebSocket server support 487 | 488 | Enabled Component config->HTTP Server->ESP_HTTPS_SERVER support 489 | 490 | Enabled Component config->mbedTLS->HKDF algortithm 491 | 492 | Enabled Component config->mbedTLS->Expiry verification 493 | 494 | Disabled Component config->mbedTLS->Support TLS 1.0 495 | 496 | Compiler options -> Optimize for size 497 | 498 | Compiler options -> Assertion level -> Silent 499 | 500 | Compiler options -> Enable C++ Exceptions 501 | 502 | Component config -> Log Output set to error only 503 | 504 | ## 2021-05-02 505 | ### SWITCH TO IDF Framework 506 | - [x] platformio.ini modifications 507 | - [x] Enabled mbedtls hkdf 508 | - [x] Partition table 509 | - [x] Code changes from Serial. to standard printf / cout 510 | - [x] Rewrite JSON uing framework cJSON 511 | - [x] Rewrite 512 | 513 | ## 2021-05-01 514 | * Base64 fix for the omitted '='/'==' ending in ntor key, causing handshake failures 515 | * Key exchange was wrong, doing corrections 516 | * Rename CertificateUtils class to CryptoUtils class 517 | 518 | ### The big problem 519 | Found that Arduino framework with the latest IDF and C++17 has too much size on RAM limited to 320KB. When generating curve25519 keys an error about BIGNUM trying to allocate too much memory has been thrown and there is no way to avoid. 520 | 521 | However seems that IDF framework (from Espressif) is a much better and flexible solution. With some tests I got the proof. IDF has builtin, fully configurable libraries also to manage JSON if needed. So switching the project to IDF it's a must. Found how to use C++17, easy. 522 | 523 | For educational purposes, the **current, unusable** project sources will be placed in a different branch called "main-arduino-not-working". 524 | 525 | ## 2021-04-25 526 | * Added authoritiy directory list for descriptors query after reading dir-spec.txt 527 | * Debug/Verbose available as constexpr only 528 | * Switched to hxx + cpp structure (things are going to be complicated) 529 | * Added realay descriptor NTOR Onion Key for handshakes 530 | * Test new cache success 531 | * Added function to avoid same-family nodes 532 | * Changes and optimizations 533 | * Send NETINFO cell after CERTS cell authentication 534 | 535 | ## 2021-04-24 536 | 537 | * Switch to a better file-cached Onionoo lists (also according to the *"...we build circuits when we have enough directory info to do it..."*) 538 | * Remove limit and old methods in RelaySearcher class 539 | * Wrote certificate validation methods (one is still pending for unclear statement _"The certified key in the Link certificate matches the link key that was used to negotiate the TLS connection"_) **I had a lot of pain with CERTS cell!!!** 540 | 541 | 542 | ## No enough flash space first problem [SOLVED] 543 | Today first error: The program size (1 393 964 bytes) is greater than maximum allowed (1310720 bytes). 544 | AFTER REMOVAL OF ARDUINOJSON => Error: The program size (1 385 416 bytes) is greater than maximum allowed (1310720 bytes). 545 | ### Possible solutions and checks: 546 | - [x] Remove ArduinoJson library (check weight) and switch to a better Onionoo request & caching (~250KB max per file/request leds to at least 750KB filesystem free space) 547 | Not the right way! Program size with almost no changes 548 | - [x] Use LittleFS rather than SPIFFS (check weight) 549 | Not the right way! Think no significative changes 550 | - [x] Use another partition table and check file system free space is enough for future improvements 551 | Needed at least 750KB free SPIFFS storage. No OTA required. 552 | 553 | That's it! Switching to no_ota.csv in platformio.ini leds to: 554 | 555 | Flash: [======= ] 66.5% (used 1393964 bytes from 2097152 bytes) 556 | 557 | maybe if this error will take plae again switch to huge_app.csv (no ota, program up to 3.145.728 bytes and SPIFFS of ~900KB) 558 | 559 | ## 2021-04-23 560 | 561 | * Got first space problem! 562 | * Added an utility class for certificate utilities if the mbedtls library will change in future 563 | * Solved mbedtls signature verification (see https://github.com/ARMmbed/mbedtls/issues/4400) 564 | * Added expcted or not response parameter to raw request method 565 | * Changed classes to manage certificates with polymorphism and base:derived 566 | * Added Tor's Ed25519 certificate managing class 567 | * More CERTS cell validations done 568 | 569 | ## 2021-04-18 570 | * Added more commands for debugging and normal use 571 | * RSA certificates validation is ready (using ESP32 mbedtls library) 572 | * First cells exchange with Guard node working!! 573 | * Added a smart (but will do better) method to get needed relays 574 | * TLS connection working 575 | * Added class to manage cells, circuit, relay, certificates, general networking 576 | * Added NTP time sync at ESP32 boot 577 | * Encrypted AES128 config file working (SPIFFS filesystem) 578 | * Memory checks are OK! 579 | 580 | ## 2021-04-18 581 | At the moment just a non-working draft! 582 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # toresp32 - Tor for IoT 2 | Briand's project to turn an ESP32 into a Tor client "plug&play" 3 | 4 | ## Development status 5 | 6 | For details check always [NEWS FILE](NEWS.md) 7 | 8 | **v1.1.0 RELEASE AVAILABLE [link to release v1.1.0](https://github.com/briand-hub/toresp32/releases/tag/v1.1.0)** 9 | 10 | * Working to **version 1.1.0**, new features [See full changelog](https://github.com/briand-hub/toresp32/wiki/Version-1.1.0-Changelog): 11 | * consensus for cache (no more microdescriptors) 12 | * exit policy check with default ports 13 | * faster proxy with async and parallel read/write (thread safe), custom port enabled. 14 | * 8 ready circuits 15 | * better performances 16 | * less memory used 17 | * better log output 18 | * support for ESP32-S2 and ESP32-WRover, full support for SPI RAM 19 | * statistics 20 | * total debug suppression (performances) 21 | * new commands 22 | 23 | **FIRST RELEASE AVAILABLE [link to release v1.0.0](https://github.com/briand-hub/toresp32/releases/tag/v1.0.0)** 24 | 25 | * 08/2021 Ready to release 26 | * 08/2021 Proxy working through Tor for HTTP/HTTPS requests! 27 | * 07/2021 With updated [library](https://www.github.com/briand-hub/LibBriandIDF) and small modifications now this project can work both on ESP32 and Linux systems (see details below) 28 | * 07/2021 Working with multiple circuits (managed asynchronously): connection, hostname resolution 29 | * 05/2021 Switching to IDF Framework completed and obtained the first working circuit! 30 | * 04/2021 At the moment just a non-working draft! 31 | 32 | ## Intro 33 | This project borns just for personal interest on ESP32 platform (I'm using WeMos LolinD32 v.1.0.0) because it summarize my interests for electronics, programming, c++ and cryptography. I think [Tor](https://www.torproject.org/) is a great example of applied cryptography for a noble purpose. 34 | Unfortunatley Tor has little or no library and the protocol specifications/documentation is very poor. Seems also that implementations (found just two, written in C and Python) are a bit complicated to decode and catch Tor's "secrets" and moreover code is not organized in my own "way". So I decided to start this project. 35 | 36 | ## The goal 37 | The goal is to write a very simple C++17 working Tor proxy for ESP32 so the ESP32 could be attached to any computer with a bash/dos/putty client ready-to-go. 38 | Using ESP as a proxy allows to keep no traces of Tor client/browser on your computer (but traces of the navigation history and so on **are not** avoided!). 39 | 40 | ## Usage disclaimer and license 41 | This code is open source and protected by GPL v3 license, see [LICENSE FILE](LICENSE). 42 | This project is intended **only** for educational purposes and any modification, unintended use, illegal use is *your own* responsibility. 43 | This project has no warranty in any sense. 44 | 45 | ## Usage instructions 46 | 47 | See [WIKI](https://github.com/briand-hub/toresp32/wiki). 48 | 49 | **REMEMBER**: ESP32 is a 240MHz processor with 320KB of RAM. Do not expect good performances or fast webpage loading!! 50 | 51 | ## The code 52 | It is written in C++17. The project is a PlatformIO project based on WEMOS LOLIN D32 platform. The framework used is Espressif IDF 4.4. 53 | In order to enable C++17 support platformio.ini file has been edited adding reference to the last dev release of toolchain xtensa32 is upgraded to support gnu++17 keyword. Using C++17 also requires .vscode/c_cpp_properties.json edited (see platformio.ini file for specifications). 54 | I would like to keep the code well-organized and as simple as possible. I'll try to add all the documentation and useful comments where necessary. 55 | The code will implement the **current** last specifications and will not support any deprecated or *will-be-deprecated* (imho) feature. For example if I have to choose to implement hidden services, I would just write code for V3 and not any previous version (sorry, I have no time). 56 | 57 | ## Dev environment 58 | Project is built with VSCode and PlatformIO on WEMOS LOLIND32 platform and Espressif IDF 4.3 framework. 59 | 60 | ## Linux Porting 61 | 62 | Debugging and testing in ESP32 could be a very hard task. So I defined the needed IDF functions to my base [library](https://www.github.com/briand-hub/LibBriandIDF) and made the project easy to compile and debug on Linux systems (Using Debian 10.0 Buster) 63 | 64 | ### Requirements 65 | 66 | * gcc/g++ with version greater than 8.4 67 | * MbedTLS Library (*sudo apt install libmbedtls-dev*) 68 | * Sodium Library (*sudo apt install libsodium-dev*) 69 | * LibBriandIDF (see below) 70 | 71 | ## Building project 72 | 73 | ### ESP32 Environment: PlatformIO and VSCode 74 | 75 | Simply open the project with PlatformIO in VSCode, then use Build or Upload and Monitor menu. The required libraries should be automatically downloaded and installed. 76 | 77 | ### Linux Environment 78 | 79 | First, clone the repo: 80 | 81 | ```bash 82 | $ git clone https://github.com/briand-hub/toresp32 83 | ``` 84 | 85 | Install required libraries and switch the path to project root: 86 | 87 | ```bash 88 | $ sudo apt install libsodium-dev libmbedtls-dev 89 | $ cd toresp32 90 | ``` 91 | 92 | Then just clone the LibBriandIDF repo in the default path, like PlatformIO would do: 93 | 94 | ```bash 95 | toresp32$ mkdir .pio 96 | toresp32$ mkdir .pio/libdeps 97 | toresp32$ mkdir .pio/libdeps/lolin_d32 98 | toresp32$ cd .pio/libdeps/lolin_d32 99 | toresp32/.pio/libdeps/lolin_d32$ git clone https://github.com/briand-hub/LibBriandIDF 100 | ``` 101 | 102 | Ready to build, use: 103 | 104 | ```bash 105 | toresp32$ make 106 | ``` 107 | 108 | To execute: 109 | 110 | ```bash 111 | toresp32$ ./main_linux_exe 112 | ``` 113 | 114 | To debug with valgrind: 115 | 116 | ```bash 117 | toresp32$ sudo apt install valgrind 118 | toresp32$ make 119 | toresp32$ valgrind ./main_linux_exe 120 | ``` 121 | 122 | ## Challenges 123 | 124 | 1. Implement a Tor protocol with just 320KB SRAM and 4MB flash space 125 | 2. Learn-by-doing Tor protocol 126 | 3. Find the time for this project :-/ 127 | 128 | ## Task list 129 | 130 | - [x] Create base project 131 | - [x] First project commit 132 | - [x] Add MAC Change function 133 | - [x] Support for simple filesystem (SPIFFS or LittleFS) 134 | - [x] Connection parameters could be saved in a configuration file (encrypted with 16 char password / AES-128) 135 | - [x] Add a vintage logo :-) 136 | - [x] Study TOR protocol 137 | - [x] Working release 138 | 139 | ## Future ideas 140 | * Add a TRNG (true random number generator) with a Zener diode 141 | * Implement Hidden Services 142 | -------------------------------------------------------------------------------- /include/BriandDefines.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // GENERAL DEFINES / SETTINGS / PARAMETERS FOR ALL FILES 20 | // MOVED HERE ALL #include directives in order to simplify files 21 | // This settings could be changed if needed 22 | 23 | /* Avoid error of multiple definitions (first defined here...) */ 24 | #ifndef BRIANDDEFINES_H_ 25 | #define BRIANDDEFINES_H_ 26 | 27 | /* If set to 1, NO DEBUG log for components will be compiled. To have debug log on just set to 0 (#define SUPPRESSDEBUGLOG 0) */ 28 | #define SUPPRESSDEBUGLOG 1 29 | 30 | constexpr unsigned char BUILTIN_LED_MODE = 1; // Built-in led mode: 0 = OFF, 1 = ON 31 | constexpr bool CHANGE_MAC_TO_RANDOM = true; // choose if you want to change the MAC address to a random one for improved security 32 | constexpr unsigned short WIFI_CONNECTION_TIMEOUT = 90; // timeout in seconds, expired with no wifi STA connection will reboot system 33 | constexpr unsigned char WIFI_HOSTNAME_LEN = 8; // random hostname length for AP/STA 34 | constexpr unsigned char WIFI_AP_SSID_LEN = 16; // random ssid length for AP/STA 35 | constexpr unsigned char WIFI_AP_PASSWORD_LEN = 16; // random wifi password length for AP 36 | constexpr unsigned char WIFI_AP_CH = 1; // wifichannel for AP 37 | constexpr unsigned char WIFI_AP_HIDDEN = 0; // AP hidden Essid (1) or not (0) 38 | constexpr unsigned char WIFI_AP_MAX_CONN = 1; // AP maximum connections (set to 1 for more security, just you) 39 | constexpr unsigned char NET_CONNECT_TIMEOUT_S = 60; // Elapsed this number of seconds, any connection is intended to be timed out! 40 | constexpr unsigned char NET_IO_TIMEOUT_S = 30; // Timeout (seconds) for socket read/write operations (0 for unlimited) 41 | constexpr const char* NTP_SERVER = "pool.ntp.org"; // NTP server to use 42 | constexpr bool TOR_CIRCUITS_RANDOM_SKIP = false; // Skip random bytes of consensus to increase randomness of cache (however could not be a good choice for speed) 43 | constexpr unsigned short TOR_CIRCUITS_KEEPALIVE = 8; // No. of Tor circuits to be kept always open and ready (avoid more than 8 on ESP Platform without spiram!) 44 | constexpr unsigned short TOR_CIRCUITS_MAX_TIME_S = 900; // Elapsed this time (seconds) the Tor circuit will be closed automatically. 45 | constexpr unsigned short TOR_CIRCUITS_MAX_REQUESTS = 1000; // After N requests the Tor circuit will be closed and changed. 46 | constexpr unsigned char TOR_NODES_CACHE_SIZE = 20; // No. of Tor nodes, for each type (guard/exit/middle) to keep saved. (higher parameter leds to higher cache download!) 47 | constexpr unsigned char TOR_NODES_CACHE_VAL_H = 24; // Hours since the chache of nodes is considered OLD and must be downloaded again 48 | constexpr unsigned char TOR_SOCKS5_PROXY_MAX_CONN = 67; // % of maximum accepted connection accepted by proxy (Max = (TOR_SOCKS5_PROXY_MAX_CONN/100.0)*TOR_CIRCUITS_KEEPALIVE) (avoid more than 67% on ESP Platform without spiram!) 49 | constexpr unsigned short TOR_SOCKS5_PROXY_PORT = 80; // Default port of the Socks5 Proxy 50 | constexpr unsigned short TOR_SOCKS5_PROXY_TIMEOUT_S = 30; // Timeout in seconds the Socks5 Proxy select/read/write calls 51 | 52 | /** The following setting will define the size of the TOR_MUST_HAVE_PORTS array. */ 53 | constexpr const unsigned char TOR_MUST_HAVE_PORTS_SIZE = 1; 54 | /** The following setting will make relay searcher to choose only exit nodes that accept the listed ports. */ 55 | constexpr const unsigned short TOR_MUST_HAVE_PORTS[TOR_MUST_HAVE_PORTS_SIZE] = { 443 }; 56 | 57 | 58 | // Includes needed (with linux porting enabled) 59 | 60 | /* Standard C++ libraries */ 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | /* mbedtls and libsodium libraries */ 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | 89 | #ifdef MBEDTLS_HKDF_C 90 | #include 91 | #endif 92 | 93 | #if defined(ESP_PLATFORM) 94 | 95 | /* Framework libraries */ 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | // HW Accelleration by ESP32 cryptographic hardware 112 | // #include gives linker error! 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | #include 121 | 122 | /* Custom specific libraries */ 123 | #include "BriandESPDevice.hxx" 124 | #include "BriandESPHeapOptimize.hxx" 125 | #include "BriandIDFWifiManager.hxx" 126 | #include "BriandIDFSocketClient.hxx" 127 | #include "BriandIDFSocketTlsClient.hxx" 128 | // CJSON NOT NEEDED ANYMORE #include 129 | 130 | // Early declarations of ESP logging functions trick (see BriandEspLogging.cpp) 131 | 132 | /* This define, before including esp_log.h, allows log level higher than the settings in menuconfig */ 133 | #ifndef LOG_LOCAL_LEVEL 134 | #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE 135 | #endif 136 | 137 | #include 138 | 139 | void BRIAND_SET_LOG(const char*, esp_log_level_t); 140 | 141 | #if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 3, 0) 142 | esp_log_level_t esp_log_level_get(const char*); 143 | #endif 144 | 145 | #elif defined(__linux__) 146 | /* Framework libraries */ 147 | #include 148 | #include 149 | #include 150 | #include 151 | 152 | /* Custom specific libraries */ 153 | #include "BriandEspLinuxPorting.hxx" 154 | #include "BriandESPDevice.hxx" 155 | #include "BriandESPHeapOptimize.hxx" 156 | #include "BriandIDFWifiManager.hxx" 157 | #include "BriandIDFSocketClient.hxx" 158 | #include "BriandIDFSocketTlsClient.hxx" 159 | // CJSON NOT NEEDED ANYMORE #include 160 | 161 | // #include gives linker error on ESP_PLATFORM! 162 | #include 163 | 164 | /* On linux platform make mbedtls settings similar to ESP ones */ 165 | #include 166 | 167 | #ifdef MBEDTLS_SSL_IN_CONTENT_LEN 168 | #undef MBEDTLS_SSL_IN_CONTENT_LEN 169 | #endif 170 | #define MBEDTLS_SSL_IN_CONTENT_LEN 4096 171 | 172 | #ifdef MBEDTLS_SSL_OUT_CONTENT_LEN 173 | #undef MBEDTLS_SSL_OUT_CONTENT_LEN 174 | #endif 175 | #define MBEDTLS_SSL_OUT_CONTENT_LEN 2048 176 | 177 | /* Re-define project-specific IDF functions */ 178 | void BRIAND_SET_LOG(const char*, esp_log_level_t); 179 | typedef mbedtls_aes_context esp_aes_context; 180 | #define esp_aes_init mbedtls_aes_init 181 | #define esp_aes_free mbedtls_aes_free 182 | #define esp_aes_setkey mbedtls_aes_setkey_enc 183 | #define esp_aes_crypt_ctr mbedtls_aes_crypt_ctr 184 | 185 | #else 186 | #error "UNSUPPORTED PLATFORM (ESP32 OR LINUX REQUIRED)" 187 | #endif 188 | 189 | 190 | // STACK SIZE OPTIMIZATIONS 191 | 192 | 193 | #if SUPPRESSDEBUGLOG 194 | #define STACK_TorEsp32 4096 195 | #define STACK_HeapStats 768 196 | #define STACK_StaCheck 1024 197 | #define STACK_MgrInst 5120 198 | #define STACK_TorProxy 2816 199 | #define STACK_TorProxyReq 4096 200 | #define STACK_StreamWR 3584 201 | #define STACK_StreamRD 4096 202 | #else 203 | #define STACK_TorEsp32 4096 204 | #define STACK_HeapStats 1024 205 | #define STACK_StaCheck 1280 206 | #define STACK_MgrInst 5120 207 | #define STACK_TorProxy 3072 208 | #define STACK_TorProxyReq 4096 209 | #define STACK_StreamWR 4096 210 | #define STACK_StreamRD 4096 211 | #endif 212 | 213 | 214 | // ERROR CODES 215 | 216 | enum BriandError : short { 217 | /* No error */ 218 | BRIAND_ERR_NONE = 0, 219 | BRIAND_ERR_OK = 1, 220 | 221 | /* Network errors: [-1; -999] */ 222 | 223 | 224 | /* Circuit errors [-1000; -1999] */ 225 | 226 | 227 | /* Cell generic errors [-2000; -2999] */ 228 | 229 | BRIAND_ERR_INSUFFICIENT_PAYLOAD_BYTES = -2000, 230 | 231 | /* Relay cell errors [-3000; -3999] */ 232 | 233 | BRIAND_ERR_NOT_RELAY_CELL = -3000, 234 | BRIAND_ERR_RECOGNIZED_NOT_ZERO = -3001, 235 | BRIAND_ERR_STREAMID_NOT_MATCHING_NOR_ZERO = -3002, 236 | BRIAND_ERR_DIGEST_NOT_MATCHING = -3003, 237 | 238 | /* Searcher/cache errors [-4000; -4999] */ 239 | 240 | BRIAND_ERR_GUARD_CACHE_INVALID = -4000, 241 | BRIAND_ERR_MIDDLE_CACHE_INVALID = -4001, 242 | BRIAND_ERR_EXIT_CACHE_INVALID = -4002, 243 | BRIAND_ERR_CACHE_INVALID_LINE = -4003 244 | 245 | }; 246 | 247 | #endif /* BRIANDDEFINES_H_ */ 248 | 249 | -------------------------------------------------------------------------------- /include/BriandNet.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | 23 | /* This file contains static class to perform network communications */ 24 | 25 | using namespace std; 26 | 27 | namespace Briand 28 | { 29 | /** This class has members to manage the Network request/response and utility methods */ 30 | class BriandNet { 31 | public: 32 | 33 | static const char* LOGTAG; 34 | 35 | /** 36 | * Method to convert a string to a vector pointer 37 | * @param input pointer to input string 38 | * @param emptyContents set it to true if you want the input buffer empty after request. false to keep it. 39 | * @return vector pointer containing the string contents 40 | */ 41 | static unique_ptr> StringToUnsignedCharVector(unique_ptr& input, bool emptyContents = true); 42 | 43 | /** 44 | * Method to convert a string to a vector pointer 45 | * @param vector pointer containing the contents 46 | * @param emptyContents set it to true if you want the input buffer empty after request. false to keep it. 47 | * @return Pointer to the output string 48 | */ 49 | static unique_ptr UnsignedCharVectorToString(unique_ptr>& input, bool emptyContents = true); 50 | 51 | /** 52 | * Method send raw bytes to specified host using BriandIDFSocketClient and returns raw response bytes. 53 | * @param host Hostname / IP 54 | * @param port Port 55 | * @param content Request (raw bytes) to send (c++ vector must be used) 56 | * @param emptyContents set it to true if you want the input buffer empty after request. false to keep it. 57 | * @return an unique_ptr to the response buffer (c++ vector), empty vector if fails 58 | */ 59 | static unique_ptr> RawInsecureRequest(const string& host, const short& port, unique_ptr>& content, bool emptyContents = true); 60 | 61 | /** 62 | * Method send raw bytes to specified host using yout own connected and ready to go BriandIDFSocketTlsClient, returns raw response bytes. 63 | * The client must be setup with certificates if validation is wanted. 64 | * @param client Pointer to your own initialized BriandIDFSocketTlsClient, connected and ready. 65 | * @param content Request (raw bytes) to send (c++ vector must be used) 66 | * @param emptyContents set it to true if you want the input buffer empty after request. false to keep it. 67 | * @param closeConnection set it to true if you want close the connection (client->end). 68 | * @param expectResponse set it to false if a response is not expected. 69 | * @return an unique_ptr to the response buffer (c++ vector), empty vector if fails or response is not expected. 70 | */ 71 | static unique_ptr> RawSecureRequest(const unique_ptr& client, unique_ptr>& content, bool emptyContents = true, bool closeConnection = false, bool expectResponse = true); 72 | 73 | /** 74 | * Method send raw bytes to specified host using BriandIDFSocketTlsClient and returns raw response bytes. 75 | * @param host Hostname / IP 76 | * @param port Port 77 | * @param content Request (raw bytes) to send (c++ vector must be used) 78 | * @param emptyContents set it to true if you want the input buffer empty after request. false to keep it. 79 | * @param pemCAcert The PEM-format certificate CA root. If nullptr, INSECURE mode will be used (unless DER certificate furnished) 80 | * @param derCAcert The DER-format certificate CA root. If nullptr, INSECURE mode will be used (unless PEM certificate furnished) 81 | * @return an unique_ptr to the response buffer (c++ vector), empty vector if fails 82 | */ 83 | static unique_ptr> RawSecureRequest(const string& host, const short& port, unique_ptr>& content, bool emptyContents = true, const unique_ptr& pemCAcert = nullptr, const unique_ptr>& derCAcert = nullptr); 84 | 85 | /** 86 | * Method send an HttpS request and returns contents in string format 87 | * @param host Hostname/IP (ex. ifconfig.me) 88 | * @param port Port (ex. 443) 89 | * @param path URI path, starting with / (ex. /all.json , /do?search=query) must be URL ENCODED before! 90 | * @param httpReturnCode if success HTTP code (200/404/500..) if fails 0 91 | * @param agent User-Agent to set in the header 92 | * @param returnBodyOnly If true just body, without headers, is returned 93 | * @param pemCAcert The PEM-format certificate CA root. If nullptr, INSECURE mode will be used (unless DER certificate furnished) 94 | * @param derCAcert The DER-format certificate CA root. If nullptr, INSECURE mode will be used (unless PEM certificate furnished) 95 | * @return Response string pointer, nullptr if fails 96 | */ 97 | static unique_ptr HttpsGet(const string& host, const short& port, const string& path, short& httpReturnCode, const string& agent = "empty", const bool& returnBodyOnly = false, const unique_ptr& pemCAcert = nullptr, const unique_ptr>& derCAcert = nullptr); 98 | 99 | /** 100 | * Method send an Http (NOT HTTPS!) request and returns contents in string format 101 | * @param host Hostname/IP (ex. ifconfig.me) 102 | * @param port Port (ex. 443) 103 | * @param path URI path, starting with / (ex. /all.json , /do?search=query) must be URL ENCODED before! 104 | * @param httpReturnCode if success HTTP code (200/404/500..) if fails 0 105 | * @param agent User-Agent to set in the header 106 | * @param returnBodyOnly If true just body, without headers, is returned 107 | * @return Response string pointer, nullptr if fails 108 | */ 109 | static unique_ptr HttpInsecureGet(const string& host, const short& port, const string& path, short& httpReturnCode, const string& agent = "empty", const bool& returnBodyOnly = false); 110 | }; 111 | } -------------------------------------------------------------------------------- /include/BriandTorAes.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | 23 | using namespace std; 24 | 25 | namespace Briand { 26 | class BriandTorAes { 27 | private: 28 | const unsigned short AES_BLOCK_SIZE_BYTES = 16; 29 | 30 | public: 31 | 32 | static string aes_encrypt(const string& input, const string& key) { 33 | constexpr unsigned short BLOCK_SIZE_BYTES = 16; 34 | 35 | unsigned char iv[BLOCK_SIZE_BYTES] = { 0x00 }; // zero-init IV 36 | size_t nonce_size = 0; 37 | unsigned char nonce_counter[BLOCK_SIZE_BYTES] = { 0x00 }; 38 | unsigned char outBuffer[input.length()] = { 0x00 }; 39 | 40 | string output(""); 41 | 42 | // Key size check (16 AES128 / 32 AES256) 43 | // ... TODO 44 | 45 | mbedtls_aes_context aes_context; 46 | 47 | // Init AES 48 | mbedtls_aes_init(&aes_context); 49 | 50 | 51 | // Set ENC key, first param context pointer, second the key, third the key-len in BITS 52 | mbedtls_aes_setkey_enc(&aes_context, reinterpret_cast(key.c_str()), key.length() * 8); 53 | 54 | // Encrypt (only CBC mode makes 16-bytes per round, CTR has not this problem with input) 55 | mbedtls_aes_crypt_ctr(&aes_context, input.length(), &nonce_size, nonce_counter, iv, reinterpret_cast(input.c_str()), outBuffer); 56 | 57 | // Free context 58 | mbedtls_aes_free(&aes_context); 59 | 60 | output.resize(input.length()); 61 | for (int i=0; i(key.c_str()), key.length() * 8); 88 | 89 | // Encrypt (only CBC mode makes 16-bytes per round, CTR has not this problem with input) 90 | mbedtls_aes_crypt_ctr(&aes_context, input.length(), &nonce_size, nonce_counter, iv, reinterpret_cast(input.c_str()), outBuffer); 91 | 92 | // Free context 93 | mbedtls_aes_free(&aes_context); 94 | 95 | output.resize(input.length()); 96 | for (int i=0; i(input.at(i)) << " "; 108 | } 109 | return s.str(); 110 | } 111 | }; 112 | } 113 | -------------------------------------------------------------------------------- /include/BriandTorCell.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorDefinitions.hxx" 23 | #include "BriandUtils.hxx" 24 | #include "BriandTorCertificates.hxx" 25 | #include "BriandTorRelay.hxx" 26 | 27 | using namespace std; 28 | 29 | namespace Briand { 30 | 31 | /** 32 | * This class represents a tor packet (cell) 33 | */ 34 | class BriandTorCell { 35 | protected: 36 | 37 | /** Flag, true if this is a variable len cell */ 38 | bool isVariableLengthCell; 39 | /** The cell's link protocol version */ 40 | unsigned short linkProtocolVersion; 41 | /** Cell total size in bytes */ 42 | unsigned long cellTotalSizeBytes; 43 | 44 | /** 45 | * CircID is 4 bytes in link protocol 4+ , 2 otherwise 46 | * The first VERSIONS cell, and any cells sent before the first VERSIONS cell, always have CIRCID_LEN == 2 for backward compatibility. 47 | */ 48 | unsigned int CircID; 49 | 50 | /** The cell command */ 51 | Briand::BriandTorCellCommand Command; 52 | 53 | /* The length in case of variable cells will be calculated from vector (length occupy 2 bytes) */ 54 | unique_ptr> Payload; 55 | 56 | /* RELAY cell Command */ 57 | BriandTorCellRelayCommand RelayCommand; 58 | 59 | /* RELAY cell Stream ID */ 60 | unsigned short StreamID; 61 | 62 | /* RELAY cell Recognized */ 63 | unsigned short Recognized; 64 | 65 | /* RELAY cell Digest (first 4 bytes) */ 66 | unsigned int Digest; 67 | 68 | /* RELAY cell Digest (all bytes) */ 69 | unique_ptr> FullDigest; 70 | 71 | /** Pads the payload (if needed) */ 72 | void PadPayload(); 73 | 74 | public: 75 | 76 | static const char* LOGTAG; 77 | 78 | /* Apr 2021: The longest allowable cell payload, in bytes. (509) */ 79 | static const short PAYLOAD_LEN = 509; 80 | 81 | /* Apr 2021: The longest allowable cell size (for fixed size) */ 82 | static const short MAX_CELL_SIZE = 514; 83 | 84 | /** 85 | * Constructor 86 | * @param link_protocol_version must be 1,2,3,4 87 | * @param circid the CircID 88 | * @param command the cell Command 89 | */ 90 | BriandTorCell(const unsigned char& link_protocol_version, const unsigned int& circid, const Briand::BriandTorCellCommand& command); 91 | 92 | ~BriandTorCell(); 93 | 94 | /** 95 | * Append one single byte to the current payload. 96 | * Warning! Do exceed PAYLOAD_LEN! 97 | * @param byte Byte-Content to append 98 | * @return true if success, false if exceed PAYLOAD_LEN 99 | */ 100 | bool AppendToPayload(const unsigned char& byte); 101 | 102 | /** 103 | * Append two bytes at once to the current payload. 104 | * Warning! Do exceed PAYLOAD_LEN! 105 | * @param what Content to append 106 | * @return true if success, false if exceed PAYLOAD_LEN 107 | */ 108 | bool AppendTwoBytesToPayload(const unsigned short& what); 109 | 110 | /** 111 | * Append 4 bytes at once to the current payload. 112 | * Warning! Do exceed PAYLOAD_LEN! 113 | * @param what Content to append 114 | * @return true if success, false if exceed PAYLOAD_LEN 115 | */ 116 | bool AppendFourBytesToPayload(const unsigned int& what); 117 | 118 | /** 119 | * Append bunch bytes at once to the current payload. 120 | * Warning! Do exceed PAYLOAD_LEN! 121 | * @param what Content to append 122 | * @return true if success, false if exceed PAYLOAD_LEN 123 | */ 124 | bool AppendBytesToPayload(vector& what); 125 | 126 | /** 127 | * Clear the current payload 128 | */ 129 | void ClearPayload(); 130 | 131 | /** 132 | * Print out the cell raw bytes to Serial output (all bytes one row) 133 | */ 134 | void PrintCellPayloadToSerial(); 135 | 136 | /** 137 | * Method to send cell over the net using the initialized and connected client secure. Cell must have Payload ready before calling! 138 | * @param client Pointer to your own initialized BriandIDFSocketTlsClient, connected and ready. 139 | * @param closeConnection set it to true if you want close the connection (client->end). 140 | * @param expectResponse set to true if should wait for response, false instead (in this case output vector will be empty) 141 | * @return Pointer to response contents 142 | */ 143 | unique_ptr> SendCell(unique_ptr& client, bool closeConnection = false, bool expectResponse = true); 144 | 145 | /** 146 | * Method to rebuild cell informations starting from a buffer received. Could override link protocol version. 147 | * @param buffer Pointer to the buffer 148 | * @param link_protocol_version Set to <= 0 to keep the default (from constructor), or set the version (>0) to override. 149 | * @return true if success, false instead. 150 | */ 151 | bool BuildFromBuffer(unique_ptr>& buffer, const unsigned char& link_protocol_version); 152 | 153 | /** 154 | * Method must be called after BuildFromBuffer and rebuilds RELAY cell informations starting from the payload received. 155 | * Payload must be previously decrypted with PeelOnionSkin method. After calling this method the Payload field will contain 156 | * only the real payload data. Also padding bytes will be deleted. 157 | * @param digestBackward The backward digest (will be updated) 158 | * @return true if success, false instead. 159 | */ 160 | bool BuildRelayCellFromPayload(unique_ptr& digestBackward); 161 | 162 | /** 163 | * @return Cell command 164 | */ 165 | Briand::BriandTorCellCommand GetCommand(); 166 | 167 | /** 168 | * @return RELAY Cell command 169 | */ 170 | Briand::BriandTorCellRelayCommand GetRelayCommand(); 171 | 172 | /** 173 | * @return Raw payload pointer reference (PAY(load) ATTENTION!) 174 | */ 175 | unique_ptr>& GetPayload(); 176 | 177 | /** 178 | * @return CircID 179 | */ 180 | unsigned int GetCircID(); 181 | 182 | /** 183 | * @return true if is a variable-length cell 184 | */ 185 | bool IsVariableLengthCell(); 186 | 187 | /** 188 | * @return Cell size in bytes (available only after SendCell or BuildFromBuffer calls) 189 | */ 190 | unsigned long int GetCellTotalSizeBytes(); 191 | 192 | /** 193 | * Method returns the highest link protocol available from a VERSION cell. Zero if non a version cell or error. 194 | * @return Highest link protocol version, 0 if not a VERSION cell or error. 195 | */ 196 | unsigned short GetLinkProtocolFromVersionCell(); 197 | 198 | /** 199 | * Method sets the certificates included in a CERTS cell to the specified relay 200 | * @param relay The relay where save certificates. 201 | * @return true if success, false if fails. 202 | */ 203 | bool SetRelayCertificatesFromCertsCell(unique_ptr& relay); 204 | 205 | /** 206 | * Method builds this cell as a fresh netinfo. Constructor must have been called 207 | * with right link protocol version, CircID and command. 208 | * @param yourIP the WAN IP 209 | */ 210 | void BuildAsNETINFO(const struct in_addr& yourPublicIP); 211 | 212 | /** 213 | * Method builds this cell as a fresh CREATE2 to exchange with the specified relay. 214 | * Constructor must have been called with right link protocol version, CircID and command. 215 | * Relay will have it's ECDH context initialized after this function (if a previous one was initialize, will be lost!) 216 | * @param relay The destination node 217 | * @return true if success, false instead. 218 | */ 219 | bool BuildAsCREATE2(BriandTorRelay& relay); 220 | 221 | /** 222 | * Method builds this cell as a fresh EXTEND2 to extend a created circuit with the specified relay. 223 | * Constructor must have been called with right link protocol version, CircID and command. 224 | * Relay will have it's ECDH context initialized after this function (if a previous one was initialize, will be lost!). 225 | * After calling this method, ApplyOnionSkin must be called. 226 | * @param extendWithRelay The destination node to extend the circuit to 227 | * @return true if success, false instead. 228 | */ 229 | bool BuildAsEXTEND2(BriandTorRelay& extendWithRelay); 230 | 231 | /** 232 | * Method applies the onion skin (AES128CTR) to the cell's payload with the given key. 233 | * @param key Encryption key 234 | */ 235 | void ApplyOnionSkin(BriandTorRelay& relay); 236 | 237 | /** 238 | * Method peels out the onion skin (AES128CTR) to the cell's payload with the given key. 239 | * @param key Decryption key 240 | */ 241 | void PeelOnionSkin(BriandTorRelay& relay); 242 | 243 | /** 244 | * Returns the relay cell's StreamID 245 | * @return the stream ID 246 | */ 247 | unsigned short GetStreamID(); 248 | 249 | /** 250 | * Returns the relay cell's Recognized 251 | * @return the stream ID 252 | */ 253 | unsigned short GetRecognized(); 254 | 255 | /** 256 | * Returns the relay cell's Digest 257 | * @return Pointer to digest, nullptr if not available 258 | */ 259 | unique_ptr>& GetRelayCellDigest(); 260 | 261 | /** 262 | * Prepare this as a RELAY cell header for sending a relay cell, based on the current cell->Payload that MUST be ready (not encrypted) 263 | * and NOT PADDED (in order to calculate correct size). Padding will be done inside this method. 264 | * @param command The relay command 265 | * @param streamID The Stream ID 266 | * @param digestForward The forward digest of the destination relay (will be updated) 267 | */ 268 | void PrepareAsRelayCell(const BriandTorCellRelayCommand& command, const unsigned short& streamID, unique_ptr& digestForward); 269 | 270 | /** 271 | * Check if the cell is recognized after peeling out onion skins. Method will check if Recognized=0 and the digest matches. 272 | * @param streamID The expected streamid 273 | * @param digestBackward The backward digest (will NOT be updated) 274 | * @return BriandError::OK if success 275 | */ 276 | BriandError IsRelayCellRecognized(const unsigned short& streamID, const unique_ptr& digestBackward); 277 | }; 278 | 279 | /* 280 | APRIL 2021 Instructions 281 | The interpretation of 'Payload' depends on the type of the cell. 282 | 283 | VPADDING/PADDING: Payload contains padding bytes. 284 | CREATE/CREATE2: Payload contains the handshake challenge. 285 | CREATED/CREATED2: Payload contains the handshake response. 286 | RELAY/RELAY_EARLY: Payload contains the relay header and relay body. 287 | DESTROY: Payload contains a reason for closing the circuit. (see 5.4) 288 | 289 | Upon receiving any other value for the command field, an OR must 290 | drop the cell. Since more cell types may be added in the future, ORs 291 | should generally not warn when encountering unrecognized commands. 292 | */ 293 | } -------------------------------------------------------------------------------- /include/BriandTorCertificates.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorDefinitions.hxx" 23 | 24 | using namespace std; 25 | 26 | namespace Briand { 27 | 28 | /** 29 | * Base class just to define common methods and fields to simplify code. Valid for some certificates. 30 | */ 31 | class BriandTorCertificateBase : public BriandESPHeapOptimize { 32 | protected: 33 | 34 | public: 35 | 36 | static const char* LOGTAG; 37 | 38 | /** Cert Type */ 39 | unsigned char Type; 40 | /** Maximum allowed certType */ 41 | static const unsigned char MAX_CERT_VALUE = 7; 42 | /** Content bytes of the certificate (raw, not including header) */ 43 | unique_ptr> Contents; 44 | 45 | /** Constructor inits the Contents vector */ 46 | BriandTorCertificateBase(); 47 | 48 | /** Copy constructor to avoid error "use of deleted function..." */ 49 | BriandTorCertificateBase(const BriandTorCertificateBase& other); 50 | 51 | /** Destructor */ 52 | ~BriandTorCertificateBase(); 53 | 54 | /** 55 | * Method return certificate name human-readable (for debug). MUST be implemented by derived classes. 56 | * @return Certificate name (string) 57 | */ 58 | virtual string GetCertificateName() = 0; 59 | 60 | /** 61 | * Method return string containing certificate type and raw bytes 62 | * @return string with short info 63 | */ 64 | string GetCertificateShortInfo(); 65 | 66 | /** 67 | * Print to serial certificate informations (debug) 68 | */ 69 | virtual void PrintCertInfo(); 70 | 71 | /** Inherited from BriandESPHeapOptimize */ 72 | virtual void PrintObjectSizeInfo(); 73 | /** Inherited from BriandESPHeapOptimize */ 74 | virtual size_t GetObjectSize(); 75 | 76 | }; 77 | 78 | /** 79 | * This is a support class, just keeps information about an Ed25519 certificate extension. 80 | */ 81 | class BriandTorEd25519CertificateExtension : public BriandESPHeapOptimize { 82 | public: 83 | 84 | static const char* LOGTAG; 85 | 86 | unsigned short ExtLength; // [2 bytes] 87 | unsigned char ExtType; // [1 byte] 88 | unsigned char ExtFlags; // [1 byte] 89 | unique_ptr> ExtData; // [ExtLength bytes] 90 | bool valid; // built correctly 91 | 92 | /** 93 | * Build extension starting from raw bytes. Please check valid attribute! 94 | */ 95 | BriandTorEd25519CertificateExtension(const unique_ptr>& rawdata); 96 | 97 | /** 98 | * Copy-constructor to avoid error: use of deleted function with make_unique 99 | */ 100 | BriandTorEd25519CertificateExtension(const BriandTorEd25519CertificateExtension& other); 101 | 102 | ~BriandTorEd25519CertificateExtension(); 103 | 104 | /** 105 | * Method returns extension total size in bytes 106 | * @return Extension size in bytes (header + data) 107 | */ 108 | unsigned int TotalSize(); 109 | 110 | /** Inherited from BriandESPHeapOptimize */ 111 | virtual void PrintObjectSizeInfo(); 112 | /** Inherited from BriandESPHeapOptimize */ 113 | virtual size_t GetObjectSize(); 114 | }; 115 | 116 | /** 117 | * Base class just to define common methods and fields to simplify code. Valid for Ed25519 Tor certificates. 118 | * See https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt 119 | */ 120 | class BriandTorEd25519CertificateBase : public BriandESPHeapOptimize { 121 | protected: 122 | const unsigned short certified_key_len = 32; 123 | const unsigned short signature_len = 64; 124 | bool isStructValid; 125 | /* This will hold all non-signature parts to verify signature */ 126 | unique_ptr> non_signature_parts; 127 | 128 | public: 129 | 130 | static const char* LOGTAG; 131 | 132 | /** Cert Type */ 133 | unsigned char Type; 134 | unsigned char VERSION; // [1 Byte] 135 | unsigned char CERT_TYPE; // [1 Byte] 136 | unsigned int EXPIRATION_DATE; // [4 Bytes] HOURS since Unix epoch 137 | unsigned char CERT_KEY_TYPE; // [1 byte] 138 | unique_ptr> CERTIFIED_KEY; // [32 Bytes] see certified_key_len 139 | unsigned char N_EXTENSIONS; // [1 byte] 140 | unique_ptr> EXTENSIONS; // [N_EXTENSIONS times] 141 | unique_ptr> SIGNATURE; // [64 Bytes] see signature_len 142 | 143 | /** 144 | * Constructor builds the certificate starting from the raw bytes. MUST call isStructValid() after 145 | * @param raw_bytes Raw bytes (will not be touched or modified!) 146 | */ 147 | BriandTorEd25519CertificateBase(const unique_ptr>& raw_bytes); 148 | 149 | ~BriandTorEd25519CertificateBase(); 150 | 151 | /** 152 | * Method to check if certificate has been correctly built from raw bytes 153 | * @return true if valid, false otherwise 154 | */ 155 | virtual bool IsStructureValid(); 156 | 157 | /** 158 | * Method determines if certificate is expired (passed EXPIRATION_DATE (in hours!) since Unix epoch 159 | * @return true if expired , false if not 160 | */ 161 | virtual bool IsExpired(); 162 | 163 | /** 164 | * Method verify signature is validated by another Ed25519 public key 165 | * @param ed25519PK Ed25519 public key 166 | * @return true if valid, false otherwise 167 | */ 168 | virtual bool IsSignatureIsValid(const unique_ptr>& ed25519PK); 169 | 170 | /** 171 | * Method return certificate name human-readable (for debug). MUST be implemented by derived classes. 172 | * @return Certificate name (string) 173 | */ 174 | virtual string GetCertificateName() = 0; 175 | 176 | /** 177 | * Print to serial certificate informations (debug) 178 | */ 179 | virtual void PrintCertInfo(); 180 | 181 | /** Inherited from BriandESPHeapOptimize */ 182 | virtual void PrintObjectSizeInfo(); 183 | /** Inherited from BriandESPHeapOptimize */ 184 | virtual size_t GetObjectSize(); 185 | 186 | }; 187 | 188 | /** CertType 2: RSA1024 Identity certificate, self-signed. DER encoded X509 */ 189 | class BriandTorCertificate_RSA1024Identity : public BriandTorCertificateBase { 190 | public: 191 | 192 | virtual string GetCertificateName(); 193 | 194 | /** 195 | * Method verify X.509 certificate (valid dates, signatures and chain) against itself 196 | * @param signAuthenticator CA root certificate 197 | * @return true if all valid, false otherwise 198 | */ 199 | virtual bool IsValid(); 200 | 201 | /** 202 | * Method returns the RSA key length (in bits) of this certificate 203 | * @return RSA key length in bits, 0 if error. 204 | */ 205 | virtual unsigned short GetRsaKeyLength(); 206 | 207 | }; 208 | 209 | /** CertType 7: Ed25519 identity, signed with RSA identity. Tor-specific format. 210 | * This class is useful to handle Tor specific RSA->Ed25519 Cross Certificate. 211 | * See https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt 212 | */ 213 | class BriandTorCertificate_RSAEd25519CrossCertificate : public BriandESPHeapOptimize { 214 | private: 215 | const unsigned int ed25519_key_size = 32; 216 | bool isStructValid; 217 | 218 | protected: 219 | 220 | public: 221 | 222 | static const char* LOGTAG; 223 | 224 | /** Cert Type */ 225 | unsigned char Type; 226 | unique_ptr> ED25519_KEY; // [32 bytes] 227 | unsigned int EXPIRATION_DATE; // [4 bytes] HOURS since Unix epoch 228 | unsigned char SIGLEN; // [1 byte] 229 | unique_ptr> SIGNATURE; // [SIGLEN bytes] 230 | 231 | /** 232 | * Constructor builds the certificate starting from the raw bytes. MUST call isStructValid() after 233 | * @param raw_bytes Raw bytes (will not be touched or modified!) 234 | */ 235 | BriandTorCertificate_RSAEd25519CrossCertificate(const unique_ptr>& raw_bytes); 236 | 237 | ~BriandTorCertificate_RSAEd25519CrossCertificate(); 238 | 239 | /** 240 | * Method to check if certificate has been correctly built from raw bytes 241 | * @return true if valid, false otherwise 242 | */ 243 | bool IsStructureValid(); 244 | 245 | /** 246 | * Method determines if certificate is expired (passed EXPIRATION_DATE (in hours!) since Unix epoch 247 | * @return true if expired , false if not 248 | */ 249 | bool IsExpired(); 250 | 251 | /** 252 | * Method validates the certificate (check signature validated by RSA 1024 Identity key) 253 | */ 254 | bool IsValid(const BriandTorCertificate_RSA1024Identity& signAuthenticator); 255 | 256 | /** 257 | * Print to serial certificate informations (debug) 258 | */ 259 | void PrintCertInfo(); 260 | 261 | /** Inherited from BriandESPHeapOptimize */ 262 | virtual void PrintObjectSizeInfo(); 263 | /** Inherited from BriandESPHeapOptimize */ 264 | virtual size_t GetObjectSize(); 265 | 266 | }; 267 | 268 | /** CertType 1: Link key certificate certified by RSA1024 identity. DER encoded X509 */ 269 | class BriandTorCertificate_LinkKey : public BriandTorCertificateBase { 270 | public: 271 | 272 | virtual string GetCertificateName(); 273 | 274 | /** 275 | * Method verify X.509 certificate (valid dates, signatures and chain) against the CA provided 276 | * @param signAuthenticator CA root certificate 277 | * @return true if all valid, false otherwise 278 | */ 279 | virtual bool IsValid(const BriandTorCertificate_RSA1024Identity& signAuthenticator); 280 | }; 281 | 282 | /** CertType 3: RSA1024 AUTHENTICATE cell link certificate, signed with RSA1024 key. DER encoded X509 */ 283 | class BriandTorCertificate_RSA1024AuthenticateCellLink : public BriandTorCertificateBase { 284 | public: 285 | 286 | virtual string GetCertificateName(); 287 | 288 | /** 289 | * Method verify X.509 certificate (valid dates, signatures and chain) against the CA provided 290 | * @param signAuthenticator CA root certificate 291 | * @return true if all valid, false otherwise 292 | */ 293 | virtual bool IsValid(const BriandTorCertificate_RSA1024Identity& signAuthenticator); 294 | 295 | }; 296 | 297 | /** CertType 4: Ed25519 signing key, signed with RSA1024 Identity key. Tor-specific format. */ 298 | class BriandTorCertificate_Ed25519SigningKey : public BriandTorEd25519CertificateBase { 299 | public: 300 | 301 | BriandTorCertificate_Ed25519SigningKey(const unique_ptr>& raw_bytes) : BriandTorEd25519CertificateBase(raw_bytes) {} 302 | 303 | virtual string GetCertificateName(); 304 | 305 | virtual bool IsValid(const BriandTorCertificate_RSAEd25519CrossCertificate& signAuthenticator); 306 | 307 | }; 308 | 309 | /** CertType 5: TLS link certificate, signed with ed25519 signing key. Tor-specific format. */ 310 | class BriandTorCertificate_TLSLink : public BriandTorEd25519CertificateBase { 311 | public: 312 | 313 | BriandTorCertificate_TLSLink(const unique_ptr>& raw_bytes) : BriandTorEd25519CertificateBase(raw_bytes) {} 314 | 315 | virtual string GetCertificateName(); 316 | 317 | virtual bool IsValid(const BriandTorCertificate_Ed25519SigningKey& signAuthenticator, const BriandTorCertificate_LinkKey& linkKeyCert); 318 | 319 | }; 320 | 321 | /** CertType 6: Ed25519 AUTHENTICATE cell key, signed with ed25519 signing key. Tor-specific format. */ 322 | class BriandTorCertificate_Ed25519AuthenticateCellLink : public BriandTorEd25519CertificateBase { 323 | public: 324 | 325 | BriandTorCertificate_Ed25519AuthenticateCellLink(const unique_ptr>& raw_bytes) : BriandTorEd25519CertificateBase(raw_bytes) {} 326 | 327 | virtual string GetCertificateName(); 328 | 329 | virtual bool IsValid(const BriandTorCertificate_Ed25519SigningKey& signAuthenticator); 330 | 331 | }; 332 | 333 | } -------------------------------------------------------------------------------- /include/BriandTorCircuit.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorDefinitions.hxx" 23 | #include "BriandTorCell.hxx" 24 | #include "BriandTorRelay.hxx" 25 | #include "BriandTorRelaySearcher.hxx" 26 | #include "BriandTorStatistics.hxx" 27 | 28 | using namespace std; 29 | 30 | namespace Briand { 31 | 32 | /** 33 | * This class manage a single Tor circuit 34 | */ 35 | class BriandTorCircuit : public BriandESPHeapOptimize { 36 | private: 37 | 38 | /** This is the circuit general status flag mask 39 | * The status can be managed by all extensions but 40 | * it is mandatory to set as BUSY at the beginning of each public method 41 | * and reset to not busy when returning. This will prevent tasks or threads 42 | * to kill an operation (networking operation) still executing. 43 | */ 44 | unsigned short CIRCUIT_STATUS; 45 | 46 | protected: 47 | 48 | unique_ptr relaySearcher; 49 | unsigned long int createdOn; // create timestamp 50 | unsigned long int paddingSent; // no. of padding cells sent 51 | unsigned long int paddingSentOn; // timestamp of last sent padding 52 | 53 | // Tor specific 54 | unsigned int CIRCID; // the CIRCID of this circuit 55 | unsigned short LINKPROTOCOLVERSION; // the version of this circuit 56 | unsigned short CURRENT_STREAM_ID; // the current StreamID (also used for N request used) 57 | unsigned short LAST_ENDED_STREAM_ID; // the last StreamID that was closed 58 | short CURRENT_STREAM_WINDOW; // the current (backward) stream window. Each 50 RELAY_DATA cells are exchanged a RELAY_SENDME is needed 59 | short CURRENT_CIRC_WINDOW; // the current (backward) circuit window. Each 100 RELAY_DATA cells are exchanged a RELAY_SENDME is needed 60 | shared_ptr> LD; // the latest stream *sent* RELAY_DATA cell digest (used by RELAY_SENDME) 61 | 62 | unique_ptr sClient; // Client used for communications 63 | 64 | /** 65 | * Method to cleanup pointers etc. before returning after a failed operation in BuildCircuit() 66 | */ 67 | void Cleanup(); 68 | 69 | /** 70 | * Method to choose a relay with timeouts and so on to simplify code. 71 | * @param relayType 0 for guard, 1 for middle, 2 for exit 72 | * @return true if success, false if there is no way to do it :( 73 | */ 74 | bool FindAndPopulateRelay(const unsigned char& relayType); 75 | 76 | /** 77 | * Method will send the First VERSION cell to guard node and waits for In-Protocol handshake cells 78 | * (CERTS/AUTHCHALLENGE/NETINFO). After that CERTS cell will be verified (certificate validation) and a response 79 | * with just Netinfo (no authentication) or Certs/Authenticate/Netinfo (if authenticate) cells will be sent. 80 | * WARNING : sClient MUST be initalized and connection with guard MUST be made before calling this method! 81 | * @param authenticateSelf set to true if client-authentication is requested 82 | * @return true if had success, false otherwise. 83 | */ 84 | bool StartInProtocolWithGuard(bool authenticateSelf = false); 85 | 86 | /** 87 | * Method will send the CREATE2 cell to the guard node 88 | * @return true if success, false otherwise 89 | */ 90 | bool Create2(); 91 | 92 | /** 93 | * Method continues to build a circuit with the next relay. 94 | * @param exitNode if true, uses the EXTEND2 to the exitNode, if false extends to middleNode 95 | * @return true if success, false otherwise 96 | */ 97 | bool Extend2(bool exitNode); 98 | 99 | /** 100 | * Method checks if a RELAY_SENDME (circuit-level or stream-level) is required. If so, sends. 101 | */ 102 | void TorStreamCheckSendMe(); 103 | 104 | public: 105 | 106 | static const char* LOGTAG; 107 | static const char* STREAMLOGTAG; 108 | 109 | /** 110 | * Flags to manage circuit status 111 | */ 112 | enum CircuitStatusFlag : unsigned short { 113 | NONE = 0b0000000000000000, /** No status at all, just instanced */ 114 | /** BUSY FLAG REMOVED, NOW USING MutexWrapper for thread safety */ 115 | /** BUSY = 0b0000000000000001, Busy circuit, doing something */ 116 | BUILDING = 0b0000000000000001, /** Doing build */ 117 | BUILT = 0b0000000000000010, /** Built */ 118 | STREAM_READY = 0b0000000000000100, /** Ready to stream */ 119 | STREAMING = 0b0000000000001000, /** Busy in streaming (after relay_begin, before relay_end) */ 120 | CLOSING = 0b0000000000010000, /** Is going to be closed */ 121 | CLOSED = 0b0000000000100000, /** Has been closed */ 122 | /* ...other flags here... */ 123 | CLEAN = 0b0100000000000000, /** Clean, never used for any stream cell */ 124 | DIRT = 0b1000000000000000, /** Dirt, INSTANCE has been used at least once */ 125 | }; 126 | 127 | /** An internal additional ID, use as you wish (used by CircuitsManager class) */ 128 | unsigned short internalID; 129 | 130 | /** The guard node */ 131 | unique_ptr guardNode; 132 | /** The middle node */ 133 | unique_ptr middleNode; 134 | /** The exit node */ 135 | unique_ptr exitNode; 136 | 137 | BriandTorCircuit(); 138 | 139 | ~BriandTorCircuit(); 140 | 141 | /** 142 | * Builds a new circuit 143 | * @param forceTorCacheRefresh Forces the tor cache, even if valid, to be rebuilt. 144 | * @return true on success 145 | */ 146 | bool BuildCircuit(bool forceTorCacheRefresh = false); 147 | 148 | /** 149 | * Method streams a single cell forward, ignores PADDING cells. 150 | * StreamID must be prepared (incremented) BEFORE calling this method. 151 | * Will not check RELAY_BEGIN sent, and will NOT set/unset BUSY flag. 152 | * @param command The RELAY command 153 | * @param data The payload to stream 154 | * @param overrideSID optional, ignores the current streamid and use the specified one. 155 | * @param SID optional, the streamid to override. 156 | * @return true if sent with success, false if error. 157 | */ 158 | bool TorStreamWriteData(const BriandTorCellRelayCommand& command, const unique_ptr>& data, const bool& overrideSID = false, const unsigned short& SID = 0); 159 | 160 | /** 161 | * Method reads a single backward, ignores PADDING cells. 162 | * Will not check RELAY_BEGIN sent, and will NOT set/unset BUSY flag. 163 | * @return Pointer to the read cell. Nullptr if error occours. 164 | */ 165 | unique_ptr TorStreamReadData(); 166 | 167 | /** 168 | * Method streams a single cell through an operative circuit and waits for the expected RELAY command response 169 | * or error (RELAY_END, DESTROY), ignores PADDING cells. StreamID must be prepared (incremented) BEFORE calling this method. 170 | * Will not check RELAY_BEGIN sent, and will set/unset BUSY flag. 171 | * @param command The RELAY command 172 | * @param requestPayload The payload to stream 173 | * @param waitFor The command to wait for 174 | * @return Pointer to response payload or nullptr if error occours. 175 | */ 176 | unique_ptr> TorStreamSingle(const BriandTorCellRelayCommand& command, const unique_ptr>& requestPayload, const BriandTorCellRelayCommand& waitFor); 177 | 178 | /** 179 | * Method sends a RELAY_BEGIN cell. 180 | * @param hostname The hostname 181 | * @param port The port 182 | * @return true on success, false otherwise 183 | */ 184 | bool TorStreamStart(const string& hostname, const short& port); 185 | 186 | /** 187 | * Method sends a RELAY_BEGIN cell. 188 | * @param ipv4 The IPv4 189 | * @param port The port 190 | * @return true on success, false otherwise 191 | */ 192 | bool TorStreamStart(const in_addr& ipv4, const short& port); 193 | 194 | /** 195 | * Method streams a single RELAY_DATA cell (non blocking). 196 | * @param data Data to stream (MAXIMUM 498 bytes!!!) 197 | * @param sent Set to false if any error occoured 198 | */ 199 | void TorStreamSend(const unique_ptr>& data, bool& sent); 200 | 201 | /** 202 | * Method reads a single cell back and ADDS to the buffer. Ignorable cells are returned but with canIgnore=true 203 | * @param buffer The buffer where data is ADDED. Max 498 bytes per session. 204 | * @param finished The value will be set to true if RELAY_END from node is encountered. 205 | * @param canIgnore The value will be set to true if the result of read is ignorable (ex. a PADDING cell) 206 | * @param timeout_s The timeout (in seconds to get a cell response) 207 | * @return true if success, false on error (ex. TRUNCATE/DESTROY). 208 | */ 209 | bool TorStreamRead(unique_ptr>& buffer, bool& finished, bool& canIgnore, const unsigned short& timeout_s = 60); 210 | 211 | /** 212 | * Method finishes the current data stream (write) 213 | * @return true on success, false on error 214 | */ 215 | bool TorStreamEnd(); 216 | 217 | /** 218 | * Resolves an hostname through TOR (only IPv4 at moment) 219 | * @param hostname the hostname to resolve 220 | * @return an in_addr struct with the resolved IP Address 221 | */ 222 | const in_addr TorResolve(const string& hostname); 223 | 224 | /** 225 | * Send a PADDING cell through circuit for keep-alive 226 | */ 227 | void SendPadding(); 228 | 229 | /** 230 | * Tears down the circuit. Also closes and resets the sClient! 231 | * @param reason the reason, however should be always set to zero (NONE) if client version to avoid version leaking. 232 | */ 233 | void TearDown(BriandTorDestroyReason reason = BriandTorDestroyReason::NONE); 234 | 235 | /** 236 | * Method returns this circuit ID 237 | * @return CircID 238 | */ 239 | unsigned int GetCircID(); 240 | 241 | /** 242 | * Method returns unix timestamp since circuit creation 243 | * @return Unix timestamp since circuit readyness 244 | */ 245 | unsigned long int GetCreatedOn(); 246 | 247 | /** 248 | * Method returns number of streams used (current streamID) 249 | * @return Current StreamID 250 | */ 251 | unsigned short GetCurrentStreamID(); 252 | 253 | /** 254 | * Method returns number of PADDING cells sent through circuit 255 | * @return Current count of PADDING cells sent 256 | */ 257 | unsigned long int GetSentPadding(); 258 | 259 | /** Prints the circuit informations to serial. Verbose mode only */ 260 | void PrintCircuitInfo(); 261 | 262 | /** 263 | * Set the status flag to 0 264 | * @param flag Flag to set to 1 265 | */ 266 | void StatusSetFlag(const CircuitStatusFlag& flag); 267 | 268 | /** 269 | * Set the status flag to 0 270 | * @param flag Flag to set to 0 271 | */ 272 | void StatusUnsetFlag(const CircuitStatusFlag& flag); 273 | 274 | /** 275 | * Set the status to zero then adds the given flag 276 | * @param flag Flag to set (unique) 277 | */ 278 | void StatusResetTo(const CircuitStatusFlag& flag); 279 | 280 | /** 281 | * Returns the status of a status flag 282 | * @return true if set, false otherwise 283 | */ 284 | bool StatusGetFlag(const CircuitStatusFlag& flag); 285 | 286 | /** 287 | * Method return a string with all status flags separeted by comma (DIRT,BUSY,BUILDING) 288 | * @return string with status 289 | */ 290 | string StatusGetString(); 291 | 292 | /** Inherited from BriandESPHeapOptimize */ 293 | virtual void PrintObjectSizeInfo(); 294 | /** Inherited from BriandESPHeapOptimize */ 295 | virtual size_t GetObjectSize(); 296 | 297 | }; 298 | 299 | /** Support class for thread-safe circuit handling. Is a wrapper. */ 300 | class BriandTorThreadSafeCircuit { 301 | public: 302 | std::mutex CircuitMutex; 303 | unique_ptr CircuitInstance; 304 | }; 305 | 306 | } -------------------------------------------------------------------------------- /include/BriandTorCircuitsManager.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorCircuit.hxx" 23 | 24 | using namespace std; 25 | 26 | namespace Briand { 27 | 28 | /** 29 | * This class handles Tor circuits 30 | */ 31 | class BriandTorCircuitsManager { 32 | protected: 33 | 34 | #if defined(ESP_PLATFORM) 35 | /** Task re-execution time, obtained by tests, in milliseconds. (ESP, min.15 seconds) */ 36 | static const unsigned short TASK_WAIT_BEFORE_NEXT = 15*1000; 37 | #else 38 | /** Task re-execution time, obtained by tests, in milliseconds. (Linux could be less, 5 seconds) */ 39 | static const unsigned short TASK_WAIT_BEFORE_NEXT = 5*1000; 40 | #endif 41 | 42 | /** Status of the manager */ 43 | static bool isStopped; 44 | 45 | /** The circuit pool */ 46 | static unique_ptr[]> CIRCUITS; 47 | 48 | /** Last used circuit */ 49 | unsigned short CIRCUIT_LAST_USED; 50 | 51 | /** Circuit pool size (default 3) */ 52 | static unsigned short CIRCUIT_POOL_SIZE; 53 | 54 | /** Maximum time in seconds to keep a circuit active before closing it (default 15 minutes) */ 55 | static unsigned short CIRCUIT_MAX_TIME; 56 | 57 | /** Maximum number of requests to do with the same circuit (default 15 requests) before closing it */ 58 | static unsigned short CIRCUIT_MAX_REQUESTS; 59 | 60 | /** 61 | * Method checks and restarts circuits pool with new instances if any is not instanced. 62 | * It also provides operations for all circuits pool. 63 | * Executes only if property isStopped=false 64 | * @param noparam set to NULL 65 | */ 66 | static void CircuitsTaskSingle(void* noparam); 67 | 68 | public: 69 | 70 | static const char* LOGTAG; 71 | 72 | /** Constructor */ 73 | BriandTorCircuitsManager(); 74 | 75 | /** 76 | * Constructor, with specific pool size 77 | * @param poolSize The maximum number of circuits to keep built 78 | * @param maxTime Maximum time in seconds to keep a circuit active before closing it 79 | * @param maxRequests Maximum number of requests to do with the same circuit before closing it 80 | */ 81 | BriandTorCircuitsManager(const unsigned short& poolSize, const unsigned short& maxTime, const unsigned short& maxRequests); 82 | 83 | /** Destructor */ 84 | ~BriandTorCircuitsManager(); 85 | 86 | /** 87 | * This method starts all the circuits cycle: 88 | * Checks the current circuits pool. 89 | * Closes circuits used too much or for too long time. 90 | * Builds new circuits when needed until MAX_POOL_SIZE is reached. 91 | * Sends PADDING through circuits to keep alive. 92 | */ 93 | void Start(); 94 | 95 | /** 96 | * This method stops all the circuits cycle, destroys the built ones and perform clean up. 97 | */ 98 | void Stop(); 99 | 100 | /** 101 | * This method returns a valid circuit to perform requests 102 | * @return Raw pointer to the circuit (BE CAREFUL!!), nullptr if no circuits available 103 | */ 104 | BriandTorThreadSafeCircuit* GetCircuit(); 105 | 106 | /** 107 | * Method returns true if is started 108 | * @return status 109 | */ 110 | bool IsStarted(); 111 | 112 | /** 113 | * Prints out the current circuits situation 114 | */ 115 | void PrintCircuitsInfo(); 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /include/BriandTorCryptoUtils.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandDefines.hxx" 20 | #include "BriandTorRelay.hxx" 21 | 22 | using namespace std; 23 | 24 | namespace Briand { 25 | 26 | /* This class contains utility methods to perform hashing and certificate validation, depending on the chosen implementation/library */ 27 | class BriandTorCryptoUtils { 28 | public: 29 | 30 | static const char* LOGTAG; 31 | 32 | /** 33 | * Method perform SHA256 digest on the input bytes. 34 | * @param input input bytes 35 | * @return Pointer to vector containing hash. 36 | */ 37 | static unique_ptr> GetDigest_SHA256(const unique_ptr>& input); 38 | 39 | /** 40 | * Method perform SHA1 digest on the input bytes. 41 | * @param input input bytes 42 | * @return Pointer to vector containing hash. 43 | */ 44 | static unique_ptr> GetDigest_SHA1(const unique_ptr>& input); 45 | 46 | /** 47 | * Method perform the digest (SHA1) of the running bytes sent/received with relay/relay_early cells (for handling tor node digest Df/Db) 48 | * @param relayCurrentDigest The relay's digest context whom the cell is received/sent. The digest will be updated! 49 | * @param relayCellPayload The relay cell payload (full, with digest field set to all zeros when sending cell, unencrypted when receiving cell) 50 | * @return Pointer to vector containing hash. 51 | */ 52 | static unique_ptr> GetRelayCellDigest(unique_ptr& relayCurrentDigest, const unique_ptr>& relayCellPayload); 53 | 54 | /** 55 | * Method perform HMAC-SHA256 on the input bytes. 56 | * @param input input bytes 57 | * @param key key required for HMAC 58 | * @return Pointer to vector containing result. 59 | */ 60 | static unique_ptr> GetDigest_HMAC_SHA256(const unique_ptr>& input, const unique_ptr>& key); 61 | 62 | /** 63 | * Method calculates the HKDF-SHA256 (RFC5869) from given input. 64 | * @param mExpand the info 65 | * @param keySeed the salt 66 | * @param bytesToProduce size needed 67 | * @return Pointer to bytes (of size bytesToProduce) 68 | */ 69 | static unique_ptr> Get_HKDF(const unique_ptr>& mExpand, const unique_ptr>& keySeed, const unsigned int bytesToProduce); 70 | 71 | /** 72 | * Method verifies SHA256 RSA PKCS#1 v1.5 signature 73 | * @param message The message (raw data) 74 | * @param x509DerCertificate The DER-encoded X.509 certificate containing the PublicKey (PK) to check signature 75 | * @param signature Signature bytes 76 | * @return true if valid, false instead 77 | */ 78 | static bool CheckSignature_RSASHA256(const unique_ptr>& message, const unique_ptr>& x509DerCertificate, const unique_ptr>& signature); 79 | 80 | /** 81 | * Method verifies a X.509 certificate against the provided root certificate 82 | * @param x509PeerCertificate The .509 peer certificate (DER endoded raw bytes or PEM-Encoded but with added null-termination) 83 | * @param x509CACertificate The X.509 CA certificate (DER endoded raw bytes or PEM-Encoded but with added null-termination) 84 | * @return true if valid, false instead 85 | */ 86 | static bool X509Validate(const unique_ptr>& x509PeerCertificate, const unique_ptr>& x509CACertificate); 87 | 88 | /** 89 | * Method verifies Ed25519 signature 90 | * @param message The message (raw data) 91 | * @param ed25519PK The Ed25519 public key 92 | * @param signature Signature bytes 93 | * @return true if valid, false instead 94 | */ 95 | static bool CheckSignature_Ed25519(const unique_ptr>& message, const unique_ptr>& ed25519PK, const unique_ptr>& signature); 96 | 97 | /** 98 | * Decode a base64 string to a vector 99 | * @param input The input string 100 | * @return Pointer to vector decoded content (empty if failed) 101 | */ 102 | static unique_ptr> Base64Decode(const string& input); 103 | 104 | /** 105 | * Method generates public/private ECDH keypair from Curve25519 as Tor specifications, saves to relay. Uses G=9 106 | * @param relay The relay where to save generated keys 107 | * @return true on success, false otherwise. 108 | */ 109 | static bool ECDH_Curve25519_GenKeys(BriandTorRelay& relay); 110 | 111 | /** 112 | * Method calculates the shared secret, given the private key and the server's public key. In Tor's equals to EXP(Y,x) 113 | * @param serverPublic The server public key response (Y) 114 | * @param privateKey The private key generated (x) 115 | * @return Pointer to the shared secret (empty if fails!) 116 | */ 117 | static unique_ptr> ECDH_Curve25519_ComputeSharedSecret(const unique_ptr>& serverPublic, const unique_ptr>& privateKey); 118 | 119 | /** 120 | * Method generates keypair and saves informations (keys and client to server vector) on given relay 121 | * @param relay The relay to conclude handshake with. WARNING: MUST have initialized the ECDH_CURVE25519_CONTEXT, ECDH_CURVE25519_CLIENT_TO_SERVER, 122 | * CREATED_EXTENDED_RESPONSE_SERVER_PK and CREATED_EXTENDED_RESPONSE_SERVER_AUTH fields. Fields are NOT cleared after the work. 123 | * @return true if success, false instead. If everything is ok, fields KEY_* and AES_* are populated. 124 | */ 125 | static bool NtorHandshakeComplete(BriandTorRelay& relay); 126 | 127 | /** 128 | * Method encrypt AES 128 CTR mode going to the specified relay 129 | * @param content The content 130 | * @param relay The destination relay 131 | * @return Pointer to encrypted content 132 | */ 133 | //static unique_ptr> AES128CTR_Encrypt(const unique_ptr>& content, const unique_ptr>& key); 134 | static unique_ptr> AES128CTR_Encrypt(const unique_ptr>& content, BriandTorRelay& relay); 135 | 136 | /** 137 | * Method decrypt AES 128 CTR mode coming from the specified relay 138 | * @param content The content 139 | * @param relay The source relay 140 | * @return Pointer to decrypted content 141 | */ 142 | static unique_ptr> AES128CTR_Decrypt(const unique_ptr>& content, BriandTorRelay& relay); 143 | 144 | }; 145 | } -------------------------------------------------------------------------------- /include/BriandTorDefinitions.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | 23 | /* This file contains list of classes intented to be used only as data structures, enums, constants etc. */ 24 | 25 | using namespace std; 26 | 27 | namespace Briand { 28 | 29 | /** Flags of a Tor relay */ 30 | enum BriandTorRelayFlag : unsigned short { 31 | AUTHORITY = 1 << 0, 32 | BADEXIT = 1 << 1, 33 | EXIT = 1 << 2, 34 | FAST = 1 << 3, 35 | GUARD = 1 << 4, 36 | HSDIR = 1 << 5, 37 | NOEDCONSENSUS = 1 << 6, 38 | RUNNING = 1 << 7, 39 | STABLE = 1 << 8, 40 | STABLEDESC = 1 << 9, 41 | V2DIR = 1 << 10, 42 | VALID = 1 << 11 43 | }; 44 | 45 | /** A Guard node must have this flags */ 46 | constexpr unsigned short TOR_FLAGS_GUARD_MUST_HAVE = 47 | Briand::BriandTorRelayFlag::GUARD | 48 | Briand::BriandTorRelayFlag::FAST | 49 | Briand::BriandTorRelayFlag::STABLE | 50 | Briand::BriandTorRelayFlag::VALID | 51 | Briand::BriandTorRelayFlag::V2DIR; 52 | 53 | /** An Exit node must have this flags */ 54 | constexpr unsigned short TOR_FLAGS_EXIT_MUST_HAVE = 55 | Briand::BriandTorRelayFlag::EXIT | 56 | Briand::BriandTorRelayFlag::FAST | 57 | Briand::BriandTorRelayFlag::STABLE | 58 | Briand::BriandTorRelayFlag::VALID | 59 | Briand::BriandTorRelayFlag::V2DIR; 60 | 61 | /** Any other node must have this flags */ 62 | constexpr unsigned short TOR_FLAGS_MIDDLE_MUST_HAVE = 63 | Briand::BriandTorRelayFlag::FAST | 64 | Briand::BriandTorRelayFlag::STABLE | 65 | Briand::BriandTorRelayFlag::VALID | 66 | Briand::BriandTorRelayFlag::V2DIR; 67 | 68 | /** Cell commands (unsigned int = 4 bytes in link protocol 4+ or 2 bytes in link protocol version 3-) */ 69 | enum BriandTorCellCommand : unsigned int { 70 | 71 | // Fixed size cells commands 72 | 73 | PADDING = 0 , // PADDING (Padding) (See Sec 7.2) 74 | CREATE = 1 , // CREATE (Create a circuit) (See Sec 5.1) 75 | CREATED = 2 , // CREATED (Acknowledge create) (See Sec 5.1) 76 | RELAY = 3 , // RELAY (End-to-end data) (See Sec 5.5 and 6) 77 | DESTROY = 4 , // DESTROY (Stop using a circuit) (See Sec 5.4) 78 | CREATE_FAST = 5 , // CREATE_FAST (Create a circuit, no PK) (See Sec 5.1) 79 | CREATED_FAST = 6 , // CREATED_FAST (Circuit created, no PK) (See Sec 5.1) 80 | NETINFO = 8 , // NETINFO (Time and address info) (See Sec 4.5) 81 | RELAY_EARLY = 9 , // RELAY_EARLY (End-to-end data; limited)(See Sec 5.6) 82 | CREATE2 = 10 , // CREATE2 (Extended CREATE cell) (See Sec 5.1) 83 | CREATED2 = 11 , // CREATED2 (Extended CREATED cell) (See Sec 5.1) 84 | PADDING_NEGOTIATE = 12 , // PADDING_NEGOTIATE (Padding negotiation) (See Sec 7.2) 85 | 86 | // Variable-length command values are: 87 | 88 | VERSIONS = 7 , // VERSIONS (Negotiate proto version) (See Sec 4) 89 | VPADDING = 128 , // VPADDING (Variable-length padding) (See Sec 7.2) 90 | CERTS = 129 , // CERTS (Certificates) (See Sec 4.2) 91 | AUTH_CHALLENGE = 130 , // AUTH_CHALLENGE (Challenge value) (See Sec 4.3) 92 | AUTHENTICATE = 131 , // AUTHENTICATE (Client authentication)(See Sec 4.5) 93 | AUTHORIZE = 132 // AUTHORIZE (Client authorization) (Not yet used) 94 | }; 95 | 96 | /** ED25519 certificate types (CERT_TYPE field). HAS NOTHING TO DO WITH CERTS CELL TYPES! */ 97 | enum BriandTorEd25519CerType : unsigned char { 98 | /* [00],[01],[02],[03] - Reserved to avoid conflict with types used in CERTS cells.*/ 99 | /* [07] - Reserved for RSA identity cross-certification; (see section 2.3 above, and tor-spec.txt section 4.2)*/ 100 | 101 | Ed25519_signing_key_with_an_identity_key = 4, 102 | TLS_link_certificate_signed_with_ed25519_signing_key = 5, 103 | Ed25519_authentication_key_signed_with_ed25519_signing_key = 6, 104 | 105 | OS_short_term_descriptor_signing_key = 8, // signed with blinded public key. 106 | OS_intro_point_auth_key_cross_certifies_descriptor_key = 9, 107 | ntor_onion_key_corss_certifies_ed25519_identity_key = 0xA, 108 | ntor_extra_encryption_key_corss_certifies_descriptor_key = 0xB 109 | }; 110 | 111 | /** Circuit destroy reason (or RELAY_TRUNCATED reason) */ 112 | enum BriandTorDestroyReason : unsigned char { 113 | NONE = 0, // -- NONE (No reason given.) 114 | PROTOCOL = 1, // -- PROTOCOL (Tor protocol violation.) 115 | INTERNAL = 2, // -- INTERNAL (Internal error.) 116 | REQUESTED = 3, // -- REQUESTED (A client sent a TRUNCATE command.) 117 | HIBERNATING = 4, // -- HIBERNATING (Not currently operating; trying to save bandwidth.) 118 | RESOURCELIMIT = 5, // -- RESOURCELIMIT (Out of memory, sockets, or circuit IDs.) 119 | CONNECTFAILED = 6, // -- CONNECTFAILED (Unable to reach relay.) 120 | OR_IDENTITY = 7, // -- OR_IDENTITY (Connected to relay, but its OR identity was not as expected.) 121 | CHANNEL_CLOSED = 8, // -- CHANNEL_CLOSED (The OR connection that was carrying this circuit died.) 122 | FINISHED = 9, // -- FINISHED (The circuit has expired for being dirty or old.) 123 | TIMEOUT = 10, // -- TIMEOUT (Circuit construction took too long) 124 | DESTROYED = 11, // -- DESTROYED (The circuit was destroyed w/o client TRUNCATE) 125 | NOSUCHSERVICE = 12, // -- NOSUCHSERVICE (Request for unknown hidden service) 126 | }; 127 | 128 | /** RELAY Cell commands */ 129 | enum BriandTorCellRelayCommand : unsigned char { 130 | RELAY_BEGIN = 1, // 1 -- RELAY_BEGIN [forward] 131 | RELAY_DATA = 2, // 2 -- RELAY_DATA [forward or backward] 132 | RELAY_END = 3, // 3 -- RELAY_END [forward or backward] 133 | RELAY_CONNECTED = 4, // 4 -- RELAY_CONNECTED [backward] 134 | RELAY_SENDME = 5, // 5 -- RELAY_SENDME [forward or backward] [sometimes control] 135 | RELAY_EXTEND = 6, // 6 -- RELAY_EXTEND [forward] [control] 136 | RELAY_EXTENDED = 7, // 7 -- RELAY_EXTENDED [backward] [control] 137 | RELAY_TRUNCATE = 8, // 8 -- RELAY_TRUNCATE [forward] [control] 138 | RELAY_TRUNCATED = 9, // 9 -- RELAY_TRUNCATED [backward] [control] 139 | RELAY_DROP = 10, // 10 -- RELAY_DROP [forward or backward] [control] 140 | RELAY_RESOLVE = 11, // 11 -- RELAY_RESOLVE [forward] 141 | RELAY_RESOLVED = 12, // 12 -- RELAY_RESOLVED [backward] 142 | RELAY_BEGIN_DIR = 13, // 13 -- RELAY_BEGIN_DIR [forward] 143 | RELAY_EXTEND2 = 14, // 14 -- RELAY_EXTEND2 [forward] [control] 144 | RELAY_EXTENDED2 = 15 // 15 -- RELAY_EXTENDED2 [backward] [control] 145 | 146 | // 32..40 -- Used for hidden services; see rend-spec-{v2,v3}.txt. 147 | 148 | // 41..42 -- Used for circuit padding; see Section 3 of padding-spec.txt. 149 | }; 150 | 151 | /** Enums reasons for RELAY_END cells */ 152 | enum BriandTorRelayEndReason : unsigned char { 153 | REASON_MISC = 1, 154 | REASON_RESOLVEFAILED = 2, 155 | REASON_CONNECTREFUSED = 3, 156 | REASON_EXITPOLICY = 4, 157 | REASON_DESTROY = 5, 158 | REASON_DONE = 6, 159 | REASON_TIMEOUT = 7, 160 | REASON_NOROUTE = 8, 161 | REASON_HIBERNATING = 9, 162 | REASON_INTERNAL = 10, 163 | REASON_RESOURCELIMIT = 11, 164 | REASON_CONNRESET = 12, 165 | REASON_TORPROTOCOL = 13, 166 | REASON_NOTDIRECTORY = 14 167 | }; 168 | } -------------------------------------------------------------------------------- /include/BriandTorDirAuthority.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #if defined(ESP_PLATFORM) 25 | #include 26 | #elif defined(__linux__) 27 | #include "BriandEspLinuxPorting.hxx" 28 | #else 29 | #error "UNSUPPORTED PLATFORM (ESP32 OR LINUX REQUIRED)" 30 | #endif 31 | 32 | #include "BriandIDFSocketClient.hxx" 33 | #include "BriandNet.hxx" 34 | 35 | using namespace std; 36 | 37 | namespace Briand { 38 | /** This struct represents a Tor Directory Authority */ 39 | typedef struct _BriandTorDirAuthority { 40 | const char* nickname; 41 | const char* fingerprint; 42 | const char* host; 43 | unsigned short port; 44 | } BriandTorDirAuthority; 45 | } 46 | 47 | // DIRECTORY AUTHORITY LIST 48 | 49 | constexpr unsigned short TOR_DIR_AUTHORITIES_NUMBER = 9; 50 | constexpr Briand::BriandTorDirAuthority TOR_DIR_AUTHORITIES[TOR_DIR_AUTHORITIES_NUMBER] = { 51 | { "moria1", "9695DFC35FFEB861329B9F1AB04C46397020CE31", "128.31.0.34", 9131 } 52 | , { "tor26", "847B1F850344D7876491A54892F904934E4EB85D", "86.59.21.38", 80 } 53 | , { "dizum", "7EA6EAD6FD83083C538F44038BBFA077587DD755", "45.66.33.45", 80 } 54 | , { "gabelmoo", "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281", "131.188.40.189", 80 } 55 | , { "maatuska", "BD6A829255CB08E66FBE7D3748363586E46B3810", "171.25.193.9", 443 } 56 | , { "Faravahar", "CF6D0AAFB385BE71B8E111FC5CFF4B47923733BC", "154.35.175.225", 80 } 57 | , { "longclaw", "74A910646BCEEFBCD2E874FC1DC997430F968145", "199.58.81.140", 80 } 58 | , { "bastet", "24E2F139121D4394C54B5BCC368B3B411857C413", "204.13.164.118", 80 } 59 | , { "Serge", "BA44A889E64B93FAA2B114E02C2A279A8555C533", "66.111.2.131", 9030 } 60 | //, { "dannenberg", "", "193.23.244.244", 80} 61 | }; 62 | 63 | // Defined after in BriandTorDirAuthority.cpp 64 | extern unsigned short TOR_DIR_LAST_USED; 65 | 66 | /** retrieves the best directory for speed/connection and sets to TOR_DIR_LAST_USED */ 67 | void briand_find_best_dir(); -------------------------------------------------------------------------------- /include/BriandTorEsp32Config.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandDefines.hxx" 20 | #include "BriandUtils.hxx" 21 | 22 | using namespace std; 23 | 24 | namespace Briand 25 | { 26 | /* Configuration file name */ 27 | constexpr const char* TORESP32_CONFIG_FILE_NAME = "/spiffs/torespconfig"; 28 | 29 | /** 30 | * Class to handle configuration file 31 | * If encrypted must be decrypted providing key (AES128 CTR) 32 | * Each line is one information and ends with \r\n 33 | * line 1: contains wifi ESSID 34 | * line 2: contains wifi PASSWORD 35 | * line 3: serial encryption PASSWORD (empty if none) 36 | */ 37 | class BriandTorEsp32Config { 38 | private: 39 | 40 | string enc_key; 41 | 42 | public: 43 | 44 | static const char* LOGTAG; 45 | 46 | unique_ptr Encrypt(const string& input) { 47 | constexpr unsigned short BLOCK_SIZE_BYTES = 16; 48 | 49 | unsigned int INPUT_SIZE = input.length(); 50 | unsigned char iv[BLOCK_SIZE_BYTES] = { 0x00 }; // zero-init IV 51 | size_t nonce_size = 0; 52 | unsigned char nonce_counter[BLOCK_SIZE_BYTES] = { 0x00 }; 53 | auto outBuffer = make_unique(INPUT_SIZE); 54 | 55 | esp_aes_context aes_context; 56 | 57 | // Init AES 58 | esp_aes_init(&aes_context); 59 | 60 | // Set ENC key, first param context pointer, second the key, third the key-len in BITS 61 | esp_aes_setkey(&aes_context, reinterpret_cast(this->enc_key.c_str()), this->enc_key.length() * 8); 62 | 63 | // Encrypt (only CBC mode makes 16-bytes per round, CTR has not this problem with input) 64 | esp_aes_crypt_ctr(&aes_context, INPUT_SIZE, &nonce_size, nonce_counter, iv, reinterpret_cast(input.c_str()), outBuffer.get()); 65 | 66 | // Free context 67 | esp_aes_free(&aes_context); 68 | 69 | return outBuffer; 70 | } 71 | 72 | string Decrypt(unique_ptr>& input) { 73 | constexpr unsigned short BLOCK_SIZE_BYTES = 16; 74 | 75 | unsigned char iv[BLOCK_SIZE_BYTES] = { 0x00 }; // zero-init IV 76 | size_t nonce_size = 0; 77 | unsigned char nonce_counter[BLOCK_SIZE_BYTES] = { 0x00 }; 78 | auto outBuffer = make_unique(input->size()); 79 | 80 | string output(""); 81 | 82 | esp_aes_context aes_context; 83 | 84 | // Init AES 85 | esp_aes_init(&aes_context); 86 | 87 | // Set ENC key, first param context pointer, second the key, third the key-len in BITS 88 | esp_aes_setkey(&aes_context, reinterpret_cast(this->enc_key.c_str()), this->enc_key.length() * 8); 89 | 90 | // Encrypt (only CBC mode makes 16-bytes per round, CTR has not this problem with input) 91 | esp_aes_crypt_ctr(&aes_context, input->size(), &nonce_size, nonce_counter, iv, input->data(), outBuffer.get()); 92 | 93 | // Free context 94 | esp_aes_free(&aes_context); 95 | 96 | output.resize(input->size()); 97 | for (int i=0; isize(); i++) { 98 | output.at(i) = static_cast( outBuffer[i] ); 99 | } 100 | 101 | return output; 102 | } 103 | 104 | string WESSID; 105 | string WPASSWORD; 106 | string SERIAL_ENC_KEY; 107 | 108 | /** 109 | * Constructor, you must take care of encryptionKey exactly 16 char long! 110 | */ 111 | BriandTorEsp32Config(string& encriptionKey) { 112 | this->enc_key = string(""); 113 | this->enc_key.append(encriptionKey); 114 | this->WESSID = string(""); 115 | this->WPASSWORD = string(""); 116 | this->SERIAL_ENC_KEY = string(""); 117 | } 118 | 119 | ~BriandTorEsp32Config() { 120 | this->enc_key.resize(1); 121 | this->WPASSWORD.resize(1); 122 | this->SERIAL_ENC_KEY.resize(1); 123 | } 124 | 125 | /** 126 | * Check if exists a configuration file 127 | * @return true if exists 128 | */ 129 | static bool ExistConfig() { 130 | ifstream file(TORESP32_CONFIG_FILE_NAME, ios::in); 131 | bool exists = file.good(); 132 | file.close(); 133 | 134 | return exists; 135 | } 136 | 137 | /** 138 | * Reads configuration file 139 | * @return true if OK 140 | */ 141 | bool ReadConfig() { 142 | if (!BriandTorEsp32Config::ExistConfig()) { 143 | return false; 144 | } 145 | else { 146 | ifstream f(TORESP32_CONFIG_FILE_NAME, ios::in | ios::binary); 147 | 148 | auto buffer = make_unique>(); 149 | 150 | while (f.good()) { 151 | buffer->push_back(f.get()); 152 | } 153 | f.close(); 154 | 155 | string contents = this->Decrypt(buffer); 156 | 157 | size_t pos; 158 | 159 | #if !SUPPRESSLOG 160 | ESP_LOGD(LOGTAG, "\n[DEBUG] File decrypted. Contents:"); 161 | #endif 162 | 163 | // First line => Essid 164 | pos = contents.find("\r\n"); 165 | if (pos == string::npos) return false; 166 | this->WESSID = contents.substr(0, pos); 167 | contents.erase(0, pos + 2); 168 | 169 | #if !SUPPRESSLOG 170 | ESP_LOGD(LOGTAG, "[DEBUG] Essid: %s\n", this->WESSID.c_str()); 171 | #endif 172 | 173 | // Second line => Password 174 | pos = contents.find("\r\n"); 175 | if (pos == string::npos) return false; 176 | this->WPASSWORD = contents.substr(0, pos); 177 | contents.erase(0, pos + 2); 178 | 179 | #if !SUPPRESSLOG 180 | ESP_LOGD(LOGTAG, "[DEBUG] Password: %s\n", this->WPASSWORD.c_str()); 181 | #endif 182 | 183 | // 3rd line => Serial encryption password (could be empty) 184 | pos = contents.find("\r\n"); 185 | if (pos == string::npos) return false; 186 | this->SERIAL_ENC_KEY = contents.substr(0, pos); 187 | if (this->SERIAL_ENC_KEY.length() < 16) 188 | this->SERIAL_ENC_KEY.clear(); 189 | contents.erase(0, pos + 2); 190 | 191 | #if !SUPPRESSLOG 192 | ESP_LOGD(LOGTAG, "[DEBUG] Enc KEY: %s\n", this->SERIAL_ENC_KEY.c_str()); 193 | #endif 194 | 195 | return true; 196 | } 197 | } 198 | 199 | /** 200 | * Writes configuration file 201 | */ 202 | void WriteConfig() { 203 | string contents(""); 204 | contents.append(this->WESSID); 205 | contents.append("\r\n"); 206 | 207 | contents.append(this->WPASSWORD); 208 | contents.append("\r\n"); 209 | 210 | if (this->SERIAL_ENC_KEY.length() < 16) 211 | contents.append("*\r\n"); 212 | else { 213 | contents.append(this->SERIAL_ENC_KEY); 214 | contents.append("\r\n"); 215 | } 216 | 217 | auto buffer = this->Encrypt(contents); 218 | 219 | ofstream f(TORESP32_CONFIG_FILE_NAME, ios::out | ios::binary); 220 | 221 | for (int i=0; i. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorCertificates.hxx" 23 | 24 | using namespace std; 25 | 26 | namespace Briand { 27 | /** 28 | * This class describes and keeps information about a single Tor Relay 29 | */ 30 | class BriandTorRelay : public BriandESPHeapOptimize { 31 | private: 32 | protected: 33 | 34 | public: 35 | 36 | static const char* LOGTAG; 37 | 38 | unique_ptr nickname; 39 | //unique_ptr first_address; 40 | unique_ptr address; 41 | unsigned short port; 42 | unique_ptr fingerprint; 43 | /** @deprecated unused! */ 44 | // unique_ptr effective_family; 45 | 46 | // TODO : add exit policy summary accept/reject 47 | // TODO: handle more fields (minimum necessary if needed!) 48 | 49 | unsigned short flags; 50 | 51 | // Relay Certificates (ready after a CERTS cell is sent, nullptr if not present) 52 | 53 | unique_ptr certLinkKey; 54 | unique_ptr certRsa1024Identity; 55 | unique_ptr certRsa1024AuthenticateCell; 56 | unique_ptr certEd25519SigningKey; 57 | unique_ptr certTLSLink; 58 | unique_ptr certEd25519AuthenticateCellLink; 59 | unique_ptr certRSAEd25519CrossCertificate; 60 | 61 | // Descriptor's informations (ready after a FetchDescriptors() is called, empty if not present) 62 | 63 | /* OR Onion key, BASE64 ENCODED, LITTLE ENDIAN */ 64 | unique_ptr descriptorNtorOnionKey; 65 | 66 | // Temporary Curve25519 keys for the handshake 67 | 68 | /** A Curve25519 temporary public key, LITTLE ENDIAN */ 69 | unique_ptr> CURVE25519_PUBLIC_KEY; 70 | /** A Curve25519 temporary private key, BIG ENDIAN */ 71 | unique_ptr> CURVE25519_PRIVATE_KEY; 72 | 73 | 74 | // KEY EXCHANGE FIELDS 75 | 76 | /** SERVER's PK received within CREATED2 or EXTENDED2 cell WARNING: will be used and then released so never use without check if nullptr! LITTLE ENDIAN */ 77 | unique_ptr> CREATED_EXTENDED_RESPONSE_SERVER_PK; 78 | /** SERVER's AUTH received within CREATED2 or EXTENDED2 cell WARNING: will be used and then released so never use without check if nullptr! */ 79 | unique_ptr> CREATED_EXTENDED_RESPONSE_SERVER_AUTH; 80 | /** KEYSEED calculated after receiving CREATED2 or EXTENDED2 cell WARNING: will be used and then released so never use without check if nullptr! */ 81 | unique_ptr> KEYSEED; 82 | 83 | /** ENCRYPTION AND DECRYPTION STUFF (available after the handshake is completed) */ 84 | 85 | /** This is the Df (forward digest) extracted from the HKDF-SHA256 handshaked data in Create2 or Extend2. WARNING: nullptr until handshake completed. */ 86 | unique_ptr KEY_ForwardDigest_Df; 87 | /** This is the Db (backward digest) extracted from the HKDF-SHA256 handshaked data in Create2 or Extend2. WARNING: nullptr until handshake completed. */ 88 | unique_ptr KEY_BackwardDigest_Db; 89 | /** This is the Kf (forward AES key, for encryption) extracted from the HKDF-SHA256 handshaked data in Create2 or Extend2. WARNING: nullptr until handshake completed. */ 90 | unique_ptr> KEY_Forward_Kf; 91 | /** This is the Kb (backward AES key, for decryption) extracted from the HKDF-SHA256 handshaked data in Create2 or Extend2. WARNING: nullptr until handshake completed. */ 92 | unique_ptr> KEY_Backward_Kb; 93 | /** This is a nonce used in HiddenServices in place of extracted from the HKDF-SHA256 handshaked data in Create2 or Extend2. WARNING: nullptr until handshake completed. */ 94 | unique_ptr> KEY_HiddenService_Nonce; 95 | 96 | unique_ptr AES_ForwardContext; 97 | unsigned char AES_ForwardNonceCounter[16] = {0x00}; 98 | size_t AES_ForwardNonceOffset = 0; 99 | unsigned char AES_ForwardIV[16] = {0x00}; 100 | 101 | unique_ptr AES_BackwardContext; 102 | unsigned char AES_BackwardNonceCounter[16] = {0x00}; 103 | size_t AES_BackwardNonceOffset = 0; 104 | unsigned char AES_BackwardIV[16] = {0x00}; 105 | 106 | // ------------------------------ 107 | 108 | BriandTorRelay(); 109 | 110 | ~BriandTorRelay(); 111 | 112 | /** 113 | * Method returns relay host 114 | * @return host in string format 115 | */ 116 | string GetHost(); 117 | 118 | /** 119 | * Method returns relay port 120 | * @return port 121 | */ 122 | unsigned short GetPort(); 123 | 124 | /** 125 | * Method returns number of certificate loaded in this relay 126 | */ 127 | unsigned short GetCertificateCount(); 128 | 129 | /** 130 | * Method validates certificates as required in Tor handshake protocol. 131 | * @return true if all valid, false if not. 132 | */ 133 | bool ValidateCertificates(); 134 | 135 | /** 136 | * Method fetches the relay (OR) descriptors needed by requesting it to an authority directory. 137 | * After calling this method descriptors will be populated. 138 | * @param useID an optional parameter for debugging purposes 139 | * @return true if success, false instead 140 | */ 141 | bool FetchDescriptorsFromAuthority(const unsigned int& useID = 0); 142 | 143 | /** 144 | * Method (only if debug active) print all short info of certificates, order of CertType 145 | */ 146 | void PrintAllCertificateShortInfo(); 147 | 148 | /** 149 | * Method concludes the handshake starting from a CREATED2 or EXTENDED2 cell payload. 150 | * WARNING: All resources fields associated will be used and then released. 151 | * @param created2_extended2_payload The pointer to payload of the received cell. 152 | * @return true if success, false instead. 153 | */ 154 | bool FinishHandshake(const unique_ptr>& created2_extended2_payload); 155 | 156 | /** 157 | * Method frees all certificates 158 | */ 159 | void ResetCertificates(); 160 | 161 | /** 162 | * Method (only if debug active) print short info about relay 163 | */ 164 | void PrintRelayInfo(); 165 | 166 | /** Inherited from BriandESPHeapOptimize */ 167 | virtual void PrintObjectSizeInfo(); 168 | /** Inherited from BriandESPHeapOptimize */ 169 | virtual size_t GetObjectSize(); 170 | 171 | }; 172 | 173 | } -------------------------------------------------------------------------------- /include/BriandTorRelaySearcher.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorRelay.hxx" 23 | #include "BriandTorCertificates.hxx" 24 | #include "BriandTorStatistics.hxx" 25 | 26 | using namespace std; 27 | 28 | namespace Briand { 29 | 30 | /** 31 | * This class contains methods to query for a suitable relay. 32 | * Actually any request for relay is done via Onionoo service because downloading consensus list from 33 | * authorities requires (April 2021) ~2MB space and ESP has poor. In futures more relays will be added 34 | * and this will bring to much more space required. 35 | */ 36 | class BriandTorRelaySearcher : public BriandESPHeapOptimize { 37 | private: 38 | 39 | // Linux porting requires little modification 40 | #if defined(ESP_PLATFORM) 41 | /** File name for the exit nodes cache */ 42 | const char* NODES_FILE_EXIT = "/spiffs/cache_exit"; 43 | /** File name for the guard nodes cache */ 44 | const char* NODES_FILE_GUARD = "/spiffs/cache_guard"; 45 | /** File name for the middle nodes cache */ 46 | const char* NODES_FILE_MIDDLE = "/spiffs/cache_middle"; 47 | #elif defined(__linux__) 48 | /** File name for the exit nodes cache */ 49 | const char* NODES_FILE_EXIT = "/tmp/toresp32_cache_exit"; 50 | /** File name for the guard nodes cache */ 51 | const char* NODES_FILE_GUARD = "/tmp/toresp32_cache_guard"; 52 | /** File name for the middle nodes cache */ 53 | const char* NODES_FILE_MIDDLE = "/tmp/toresp32_cache_middle"; 54 | #else 55 | #error "UNSUPPORTED PLATFORM (ESP32 OR LINUX REQUIRED)" 56 | #endif 57 | 58 | protected: 59 | 60 | unsigned short skipRandomResults; 61 | unsigned char randomPick; 62 | bool cacheValid; 63 | 64 | /** 65 | * Method to set random members 66 | */ 67 | virtual void randomize(); 68 | 69 | /** 70 | * Method refreshed node cache by downloading a fresh consensus. 71 | */ 72 | virtual void RefreshNodesCache(); 73 | 74 | /** 75 | * Method check the file cache validity. 76 | * @return true if ok, false otherwise (or cache not exist or has invalid content) 77 | */ 78 | virtual bool CheckCacheFile(const char* filename); 79 | 80 | /** 81 | * Method check if the given IPs are in the same family (first 2 octest). 82 | * @param first First IP address (ex. "61.62.3.4") 83 | * @param second Second IP address (ex. "61.64.4.5") 84 | * @return true if in the same family, false otherwise. 85 | */ 86 | virtual bool IPsInSameFamily(const string& first, const string& second); 87 | 88 | /** 89 | * Method check if a port is listed inside a list of ports. 90 | * @param port The port 91 | * @param portList A list containing a set of ports separated by comma, includes ranges: 22,80-81,443,1-20,9090 92 | */ 93 | virtual bool IsPortListed(const unsigned short& port, const string& portList); 94 | 95 | /** 96 | * Method returns the descriptor, if found, downloading from the specified dir. 97 | * WARNING: currently supports ntor-onion-key descriptor only! 98 | * @param dir the directory index to use for request 99 | * @param fingerprint the node fingerprint 100 | * @param descriptor the descriptor identifier, must include spaces (ex. "ntor-onion-key ") 101 | * @returns string with descriptor or empty string if not found 102 | */ 103 | virtual string GetDescriptor(const unsigned short& dir, const string& fingerprint,const string& descriptor); 104 | 105 | public: 106 | 107 | static const char* LOGTAG; 108 | 109 | static bool CACHE_REBUILDING; 110 | 111 | BriandTorRelaySearcher(); 112 | 113 | ~BriandTorRelaySearcher(); 114 | 115 | /** 116 | * Search for Guard node, from saved cache (if invalid will re-download) 117 | * @return A unique pointer to BriandTorRelay object if success, nullptr if fails. 118 | */ 119 | unique_ptr GetGuardRelay(); 120 | 121 | /** 122 | * Search for Middle node, from saved cache (if invalid will re-download) 123 | * @param avoidGuardIp avoids to choose a middle that is in the same family. Set it empty to allow all (not safe!) 124 | * @return A unique pointer to BriandTorRelay object if success, nullptr if fails. 125 | */ 126 | unique_ptr GetMiddleRelay(const string& avoidGuardIp); 127 | 128 | /** 129 | * Search for Exit node, from saved cache (if invalid will re-download) 130 | * @param avoidGuardIp avoids to choose an exit that is in the same family. Set it empty to allow all (not safe!) 131 | * @param avoidMiddleIp avoids to choose an exit that is in the same family. Set it empty to allow all (not safe!) 132 | * @return A unique pointer to BriandTorRelay object if success, nullptr if fails. 133 | */ 134 | unique_ptr GetExitRelay(const string& avoidGuardIp, const string& avoidMiddleIp); 135 | 136 | /** 137 | * Deletes the current stored cache 138 | * @param forceRefresh starts a new download if true 139 | */ 140 | void InvalidateCache(bool forceRefresh = false); 141 | 142 | /** 143 | * Prints the cache contents to serial output 144 | */ 145 | void PrintCacheContents(); 146 | 147 | /** Inherited from BriandESPHeapOptimize */ 148 | virtual void PrintObjectSizeInfo(); 149 | /** Inherited from BriandESPHeapOptimize */ 150 | virtual size_t GetObjectSize(); 151 | 152 | }; 153 | } -------------------------------------------------------------------------------- /include/BriandTorSocks5Proxy.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorCircuit.hxx" 23 | #include "BriandTorCircuitsManager.hxx" 24 | #include "BriandNet.hxx" 25 | #include "BriandTorStatistics.hxx" 26 | 27 | using namespace std; 28 | 29 | namespace Briand 30 | { 31 | /** This class provides a SOCKS5 Proxy using tor circuit */ 32 | class BriandTorSocks5Proxy { 33 | protected: 34 | 35 | class StreamWorkerParams { 36 | public: 37 | /** The connected client socket */ 38 | int clientSocket; 39 | /** Reference to the circuit chosen */ 40 | BriandTorThreadSafeCircuit* circuit; 41 | /** If true, there is nothing more to read from client */ 42 | bool readerFinished; 43 | /** If true, there is nothing more to write to client */ 44 | bool writerFinished; 45 | /** If true, client disconnected. */ 46 | bool clientDisconnected; 47 | /** If true, a TorStreamEnd() has been done. */ 48 | bool torStreamClosed; 49 | 50 | /** Constructor initializes with default parameters */ 51 | StreamWorkerParams() { 52 | this->clientSocket = -1; 53 | this->circuit = NULL; 54 | this->readerFinished = false; 55 | this->writerFinished = false; 56 | this->clientDisconnected = false; 57 | this->torStreamClosed = false; 58 | } 59 | 60 | /** Destructor just to check make_shared working as expected */ 61 | ~StreamWorkerParams() { 62 | #if !SUPPRESSDEBUGLOG 63 | ESP_LOGD(LOGTAG, "[DEBUG] StreamWorker has been destroyed.\n"); 64 | #endif 65 | } 66 | 67 | bool GoodForWrite() { 68 | return ( 69 | !this->clientDisconnected && 70 | !this->torStreamClosed && 71 | !this->writerFinished && 72 | circuit != NULL && 73 | circuit->CircuitInstance != NULL && 74 | clientSocket != -1 && 75 | BriandTorSocks5Proxy::proxyStarted 76 | ); 77 | } 78 | 79 | bool GoodForRead() { 80 | return ( 81 | !this->clientDisconnected && 82 | !this->torStreamClosed && 83 | !this->readerFinished && 84 | circuit != NULL && 85 | circuit->CircuitInstance != NULL && 86 | clientSocket != -1 && 87 | BriandTorSocks5Proxy::proxyStarted 88 | ); 89 | } 90 | }; 91 | 92 | /** Proxy server socket */ 93 | int proxySocket; 94 | 95 | /** Port of running proxy */ 96 | unsigned short proxyPort; 97 | 98 | /** Proxy status */ 99 | static bool proxyStarted; 100 | 101 | /** Proxy user */ 102 | static string proxyUser; 103 | 104 | /** Proxy password */ 105 | static string proxyPassword; 106 | 107 | /** Pointer to CircuitsManager instance */ 108 | static BriandTorCircuitsManager* torCircuits; 109 | 110 | /** 111 | Maximum payload available for read/write stream operations LESS 5 bytes, in order 112 | to fit this requirement: To ensure unpredictability, random bytes should be added to at least one 113 | RELAY_DATA cell within one increment window. In other word, every 100 cells (increment), random bytes should be introduced in at least one cell. 114 | */ 115 | static const unsigned short MAX_FREE_PAYLOAD = 498 - 5; 116 | 117 | /** Delay in mseconds for stream read/write operations */ 118 | static const unsigned short STREAM_WAIT_MS = 200; 119 | 120 | /** Queue of pending clients to serve (contains client sockfd) */ 121 | static queue REQUEST_QUEUE; 122 | 123 | /** Number of active serving clients */ 124 | static unsigned char CURRENT_ACTIVE_CLIENTS; 125 | 126 | /** Number of MAX requests, limits the call to HandleClient(), fixed to a % of TOR_CIRCUITS_KEEPALIVE */ 127 | static const unsigned char REQUEST_QUEUE_LIMIT = (static_cast( (TOR_SOCKS5_PROXY_MAX_CONN/100.0)*TOR_CIRCUITS_KEEPALIVE ) > 0 ? static_cast( (TOR_SOCKS5_PROXY_MAX_CONN/100.0)*TOR_CIRCUITS_KEEPALIVE ) : 1); 128 | 129 | /** 130 | * Handles a single request to this proxy (accept() and queues the request) 131 | * @param serverSock the server socket FD (int) 132 | */ 133 | static void QueueClientRequest(const int serverSock); 134 | 135 | /** 136 | * Manages the request queue, if acceptable calls HandleClient() to serve next client 137 | * @param serverSock the server socket FD (int) 138 | */ 139 | static void DeQueueClientRequest(const int serverSock); 140 | 141 | /** 142 | * Handles a single client (async) 143 | * @param clientSock the connected client socket FD (int) 144 | */ 145 | static void HandleClient(const int clientSock); 146 | 147 | /** 148 | * std::async future Handles a single client receive -> write to tor (async) 149 | * @param workerParams shared pointer to an existing instance of the StreamWorkerParams 150 | */ 151 | static void ProxyClient_AsyncStreamReader(shared_ptr swParams); 152 | 153 | /** 154 | * std::async future Handles a single tor receive -> write to client (async) 155 | * @param workerParams shared pointer to an existing instance of the StreamWorkerParams 156 | */ 157 | static void ProxyClient_AsyncStreamWriter(shared_ptr swParams); 158 | 159 | /** 160 | * Method sends an error response and close client connection 161 | * @param socket Client socket (will be closed!) 162 | * @param data Data to be sent (NULL if just socket closing is required) 163 | * @param dataLen Length of data 164 | */ 165 | static void ErrorResponse(int socket, unsigned char* data, unsigned int dataLen); 166 | 167 | public: 168 | 169 | static const char* LOGTAG; 170 | 171 | BriandTorSocks5Proxy(); 172 | ~BriandTorSocks5Proxy(); 173 | 174 | /** 175 | * Method starts the proxy and listens to the specified port. 176 | * @param port Port number 177 | * @param manager The Circuits Manager instance 178 | */ 179 | void StartProxyServer(const unsigned short& port, unique_ptr& mgr); 180 | 181 | /** 182 | * Method stops the proxy and closes any binding. 183 | */ 184 | void StopProxyServer(); 185 | 186 | /** 187 | * Method to self-test simulating a client that requests on 127.0.0.1 remote IP via APIFY. 188 | * Uses TOR network, outputs IP to stdout. 189 | */ 190 | void SelfTest(); 191 | 192 | /** 193 | * Method prints on stdout the proxy status (including credentials) 194 | */ 195 | void PrintStatus(); 196 | 197 | }; 198 | } -------------------------------------------------------------------------------- /include/BriandTorStatistics.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorCell.hxx" 23 | 24 | /* This file contains a class used for TOR statistics */ 25 | 26 | using namespace std; 27 | 28 | namespace Briand { 29 | 30 | /** Static class to manage statistics */ 31 | class BriandTorStatistics { 32 | public: 33 | 34 | /** Statistics field number of destroy/relay_end/relay_truncate for protocol */ 35 | static unsigned int STAT_NUM_PROTOCOL_ERR; 36 | /** Statistics field number of destroy/relay_end/relay_truncate for REASON_EXIT_POLICY */ 37 | static unsigned int STAT_NUM_EXIT_POLICY_ERR; 38 | /** Statistics field number oof good transmissions */ 39 | static unsigned int STAT_NUM_FINISHED; 40 | /** Statistics field number of PADDING received */ 41 | static unsigned int STAT_NUM_RECV_PADDINGS; 42 | /** Statistics field for guard node miss in cache */ 43 | static unsigned int STAT_NUM_CACHE_GUARD_MISS; 44 | /** Statistics field for middle node miss in cache */ 45 | static unsigned int STAT_NUM_CACHE_MIDDLE_MISS; 46 | /** Statistics field for exit node miss in cache */ 47 | static unsigned int STAT_NUM_CACHE_EXIT_MISS; 48 | /** Cache time build (s) */ 49 | static unsigned int STAT_CACHE_BUILD_TIME; 50 | /** No. of dropped node due to same-family ips */ 51 | static unsigned int STAT_NUM_CACHE_SAME_IP_DROP; 52 | /** No. of dropped exit node due to minimum port settings */ 53 | static unsigned int STAT_NUM_CACHE_EXIT_PORT_DROP; 54 | /** Statistics field for guard node connection error */ 55 | static unsigned int STAT_NUM_GUARD_CONN_ERR; 56 | /** Statistics field for number of descriptor fetch errors */ 57 | static unsigned int STAT_NUM_DESCRIPTOR_FETCH_ERR; 58 | /** Statistics field for no. of failed CREATE2 */ 59 | static unsigned int STAT_NUM_CREATE2_FAIL; 60 | /** Statistics field for no. of failed EXTEND2 */ 61 | static unsigned int STAT_NUM_EXTEND2_FAIL; 62 | /** No. of fetched descriptors */ 63 | static unsigned int STAT_DESCRIPTORS_N; 64 | /** Avg time to fetch a node descriptor */ 65 | static unsigned int STAT_DESCRIPTORS_TIME_AVG; 66 | /** No. of built circuits */ 67 | static unsigned int STAT_BUILT_N; 68 | /** Avg time to build a circuit, milliseconds */ 69 | static unsigned int STAT_BUILD_TIME_AVG; 70 | /** Avg time to send a stream cell through Tor, milliseconds */ 71 | static unsigned int STAT_TOR_SEND_TIME_AVG; 72 | /** No. of stream cells sent */ 73 | static unsigned int STAT_TOR_SEND_N; 74 | /** Avg time to receive a stream cell from Tor, milliseconds */ 75 | static unsigned int STAT_TOR_RECV_TIME_AVG; 76 | /** No. of stream cells sent */ 77 | static unsigned int STAT_TOR_RECV_N; 78 | 79 | BriandTorStatistics(); 80 | ~BriandTorStatistics(); 81 | 82 | /** 83 | * Save a statistical information from cell 84 | */ 85 | static void SaveStatistic(const unique_ptr& cell); 86 | 87 | /** 88 | * Save a statistical information from destroy reason / relay truncated reason 89 | */ 90 | static void SaveStatistic(const BriandTorDestroyReason& reason); 91 | 92 | /** 93 | * Save a statistical information from a relay end reason 94 | */ 95 | static void SaveStatistic(const BriandTorRelayEndReason& reason); 96 | 97 | /** 98 | * Print statistics to stdout 99 | */ 100 | static void Print(); 101 | 102 | }; 103 | } -------------------------------------------------------------------------------- /include/BriandUtils.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorDefinitions.hxx" 23 | 24 | using namespace std; 25 | 26 | namespace Briand 27 | { 28 | /* This class contains support functions used in code */ 29 | class BriandUtils { 30 | public: 31 | 32 | static const char* LOGTAG; 33 | 34 | /** 35 | * Get a random byte based on ESP32 hw 36 | * @return Random byte 37 | */ 38 | static unsigned char GetRandomByte(); 39 | 40 | /** 41 | * Get a random MAC Address 42 | * @return Random MAC, format unsigned 43 | */ 44 | static unique_ptr GetRandomMAC(); 45 | 46 | /** 47 | * Get a random Hostname 48 | * @return Random host name (ASCII alphanumeric chars) 49 | */ 50 | static unique_ptr GetRandomHostName(); 51 | 52 | /** 53 | * Get a random Hostname 54 | * @return Random host name (ASCII alphanumeric chars) 55 | */ 56 | static unique_ptr GetRandomSSID(); 57 | 58 | /** 59 | * Get a random Password of specified length 60 | * @param length Password length 61 | * @return Random password 62 | */ 63 | static unique_ptr GetRandomPassword(int length); 64 | 65 | /** 66 | * Convert flags to string with specified separator 67 | * @param flagMask Mask of flags 68 | * @param prepend Prepend this string to output flag 69 | * @param separator Output separator 70 | * @return flag string list separated by separator 71 | */ 72 | static string BriandTorRelayFlagsToString(unsigned short flagMask, const string& prepend = "", const string& separator=" "); 73 | 74 | /** 75 | * Method to get public IP address from ipify API 76 | * @return string with IP, empty if fails 77 | */ 78 | static string GetPublicIP(); 79 | 80 | /** 81 | * DEBUG Method to print raw bytes to serial output (hex format) 82 | * @param buffer the buffer to be printed (vector) 83 | * @param bytesToPrint number of buffer bytes to print (0 to print all) 84 | * @param newLineAfterBytes print a new line after N bytes (0 to print all, default) 85 | */ 86 | static void PrintByteBuffer(const vector& buffer, const short& newLineAfterBytes = 0, const unsigned int& bytesToPrint = 0); 87 | 88 | /** 89 | * DEBUG Method to print raw bytes to serial output (hex format) 90 | * @param buffer the buffer to be printed (unsigned char[]) 91 | * @param size the buffer size 92 | * @param bytesToPrint number of buffer bytes to print (0 to print all, default) 93 | * @param newLineAfterBytes print a new line after N bytes (0 to print all, default) 94 | */ 95 | static void PrintOldStyleByteBuffer(unsigned char buffer[], const unsigned int& size, const short& newLineAfterBytes = 0, const unsigned int& bytesToPrint = 0); 96 | 97 | /** 98 | * Convert a command to a readable string 99 | * @param command Cell command 100 | * @return string of command 101 | */ 102 | static string BriandTorCellCommandToString(const Briand::BriandTorCellCommand& command); 103 | 104 | /** 105 | * Convert a RELAY command to a readable string 106 | * @param command Relay Cell command 107 | * @return string of command 108 | */ 109 | static string BriandTorRelayCellCommandToString(const Briand::BriandTorCellRelayCommand& command); 110 | 111 | /** 112 | * Method return a pointer to an old-style buffer, initialized all to zero 113 | * @param size The buffer size 114 | * @return Pointer to buffer 115 | */ 116 | static unique_ptr GetOneOldBuffer(const unsigned int& size); 117 | 118 | /** 119 | * Method to get UNIX time from ESP32 120 | */ 121 | static unsigned long GetUnixTime(); 122 | 123 | /** 124 | * Helper method convert old-style buffer for libraries that needs it to vector 125 | * @param input Pointer to buffer 126 | * @param size Buffer size 127 | * @return Pointer to vector 128 | */ 129 | static unique_ptr> ArrayToVector(const unique_ptr& input, const unsigned long int& size); 130 | 131 | /** 132 | * Helper method convert string to old-style buffer for libraries that needs it. 133 | * SIZE IS THE SAME AS INPUT STRING 134 | * @param input The string 135 | * @param nullterminate If true, adds a null-terminate char 0x00 136 | * @return Pointer to buffer 137 | */ 138 | static unique_ptr StringToOldBuffer(const string& input, bool nullterminate = false); 139 | 140 | /** 141 | * Helper method convert old-style buffer for libraries that needs it to string (do not include any null-terminate!) 142 | * @param input The string 143 | * @param size The buffer size 144 | * @return The string 145 | */ 146 | static string OldBufferToString(unique_ptr& input, const unsigned long int& size); 147 | 148 | /** 149 | * Helper method convert an "hex" string to a vector 150 | * SIZE IS THE SAME AS INPUT STRING 151 | * @param hexstring The string (must be a valid hex string), each hex value must occupy 2 chars 152 | * @param preNonHex Prepend this string with a non-hex format (char to raw bytes) 153 | * @return Pointer to vector (empty vector if input string not even size) 154 | */ 155 | static unique_ptr> HexStringToVector(const string& hexstring, const string& preNonHex); 156 | 157 | /** 158 | * Helper method convert an "hex" string to an unsigned char buffer 159 | * SIZE IS THE SAME AS INPUT STRING 160 | * @param hexstring The string (must be a valid hex string), each hex value must occupy 2 chars 161 | * @param preNonHex Prepend this string with a non-hex format (raw char to bytes) 162 | * @return Pointer to buffer (all null if input string not even size) 163 | */ 164 | static unique_ptr HexStringToOldBuffer(const string& hexstring, unsigned int& size, const string& preNonhex, bool nullterm = false); 165 | 166 | /** 167 | * Prints file contents to serial output 168 | */ 169 | static void PrintFileContent(const string& filename); 170 | 171 | /** 172 | * Method removes all occurence of a char from string 173 | */ 174 | static void StringTrimAll(string& input, char c); 175 | 176 | /** 177 | * Converts an IPv4 in_addr struct to readable format 178 | * @param ip in_addr (unsigned int) IP 179 | * @return IPv4 in string format (123.456.789.000) 180 | */ 181 | static string IPv4ToString(const in_addr& ip); 182 | 183 | /** 184 | * Converts an IPv4 readable format to an in_addr struct 185 | * @param IPv4 in string format (123.456.789.000) 186 | * @return IPv4 in_addr (unsigned int) IP 187 | */ 188 | static in_addr IPv4FromString(const string& ip); 189 | 190 | /** 191 | * Converts a RELAY_END reason to human readable 192 | * @param reason RELAY_END payload 193 | * @return string containing the reason 194 | */ 195 | static string RelayEndReasonToString(const BriandTorRelayEndReason& reason); 196 | 197 | /** 198 | * Converts a RELAY_TRUNCATED or DESTROY reason to human readable 199 | * @param reason RELAY_TRUNCATED or DESTROY payload 200 | * @return string containing the reason 201 | */ 202 | static string RelayTruncatedReasonToString(const BriandTorDestroyReason& reason); 203 | 204 | /** 205 | * Checks if the provided string is a valid number 206 | * @param doubt input string 207 | * @return true if string contains only numbers 208 | */ 209 | static bool IsNumber(const string& doubt); 210 | 211 | /** 212 | * Converts an error code to string 213 | * @param errorCode Error code 214 | * @return string representing error 215 | */ 216 | static const char* BriandErrorStr(const BriandError& errorCode); 217 | 218 | }; 219 | } 220 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap 3 | nvs, data, nvs, 0x9000, 0x6000, 4 | phy_init, data, phy, 0xf000, 0x1000, 5 | factory, app, factory, 0x10000, 0x200000, 6 | spiffs, data, spiffs, 0x210000, 0x1F0000, -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env] 12 | ; Commmon settings 13 | framework = espidf 14 | platform = espressif32 15 | ;monitor and upload speed 16 | monitor_speed = 115200 17 | upload_speed = 921600 18 | ;Monitor flags 19 | monitor_filters = colorize, direct, esp32_exception_decoder 20 | ;Partitions (must be set also in menuconfig!) 21 | board_build.partitions = partitions.csv 22 | ;Custom library 23 | lib_deps = https://github.com/briand-hub/LibBriandIDF.git@1.5.0 24 | ;Enable C++17 (must be enabled also in .vscode/c_cpp_properties.json by setting "cppStandard": "c++17") 25 | build_unflags = -fno-exceptions -std=gnu++11 26 | build_flags = -fexceptions -std=gnu++17 27 | platform_packages = 28 | toolchain-xtensa32 @ ~2.80400.0 29 | 30 | [env:lolin_d32] 31 | board = lolin_d32 ; Use this for the classic ESP32 module 32 | board_build.mcu = esp32 ; WARNING: use the right chip there! 33 | 34 | [env:esp-wrover-kit] 35 | board = esp-wrover-kit ; Use this for the WRover ESP32 (contains 8MB PSram) 36 | board_build.mcu = esp32s2 ; WARNING: use the right chip there! 37 | 38 | [env:esp32-s2-saola-1] 39 | board = esp32-s2-saola-1 40 | 41 | ;[env:debug] 42 | ; JTAG Esp-prog debugging 43 | ; board = lolin_d32 ; Use this for the classic ESP32 module 44 | ; board_build.mcu = esp32 ; WARNING: use the right chip there! 45 | ; board = esp-wrover-kit ; Use this for the WRover ESP32 (contains 8MB PSram) 46 | ; board_build.mcu = esp32s2 ; WARNING: use the right chip there! 47 | ; board = esp32-s2-saola-1 ; Use this for ESP32-S2 48 | ; upload_port=COM8 49 | ; upload_protocol=esp-prog 50 | ; debug_tool=esp-prog 51 | ; build_type=debug 52 | ; debug_init_break=tbreak app_main 53 | ; debug_speed = 20000 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/BriandEspLogging.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // IDF <=v4.3 does not contain a esp_log_level_get function, but it is needed 20 | 21 | #include "BriandDefines.hxx" 22 | 23 | #if defined(ESP_PLATFORM) 24 | 25 | #if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 3, 0) 26 | 27 | // Define esp_log_level_get like the latest version, this is a trick 28 | 29 | #include 30 | 31 | // Use an efficient map! 32 | map BRIAND_LOG_LEVEL_MAP; 33 | 34 | void BRIAND_SET_LOG(const char* tag, esp_log_level_t newLevel) { 35 | // If wildcard, all to level. 36 | if (strcmp(tag, "*") == 0) { 37 | for (auto it = BRIAND_LOG_LEVEL_MAP.begin(); it != BRIAND_LOG_LEVEL_MAP.end(); ++it) { 38 | it->second = newLevel; 39 | } 40 | } 41 | else { 42 | BRIAND_LOG_LEVEL_MAP[string(tag)] = newLevel; 43 | } 44 | 45 | esp_log_level_set(tag, newLevel); 46 | } 47 | 48 | esp_log_level_t esp_log_level_get(const char* tag) { 49 | auto it = BRIAND_LOG_LEVEL_MAP.find(string(tag)); 50 | if (it == BRIAND_LOG_LEVEL_MAP.end()) BRIAND_LOG_LEVEL_MAP[string(tag)] = ESP_LOG_NONE; 51 | return BRIAND_LOG_LEVEL_MAP[string(tag)]; 52 | } 53 | 54 | #endif 55 | 56 | #elif defined(__linux__) 57 | 58 | void BRIAND_SET_LOG(const char* tag, esp_log_level_t newLevel) { 59 | // There is the base function 60 | esp_log_level_set(tag, newLevel); 61 | } 62 | 63 | #else 64 | 65 | constexpr void BRIAND_SET_LOG(const char* tag, esp_log_level_t newLevel) { /* do nothing */ }; 66 | 67 | #endif /* defined(ESP_PLATFORM) */ 68 | -------------------------------------------------------------------------------- /src/BriandNet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandNet.hxx" 20 | 21 | using namespace std; 22 | 23 | namespace Briand 24 | { 25 | const char* BriandNet::LOGTAG = "briandnet"; 26 | 27 | unique_ptr> BriandNet::StringToUnsignedCharVector(unique_ptr& input, bool emptyContents /* = true*/) { 28 | auto output = make_unique>(); 29 | output->reserve(input->size()); // allocate the right memory 30 | 31 | if (input == nullptr || input->size() == 0) { 32 | 33 | #if !SUPPRESSDEBUGLOG 34 | ESP_LOGD(LOGTAG, "[DEBUG] StringToUnsignedCharVector called with null data!\n"); 35 | #endif 36 | 37 | return output; 38 | } 39 | 40 | if (emptyContents) { 41 | while (input->length() > 0) { 42 | output->push_back( input->at(0) ); 43 | input->erase(input->begin()); 44 | } 45 | } 46 | else { 47 | for (int i=0; ilength(); i++) { 48 | output->push_back( static_cast(input->at(i)) ); 49 | } 50 | } 51 | 52 | return output; 53 | } 54 | 55 | unique_ptr BriandNet::UnsignedCharVectorToString(unique_ptr>& input, bool emptyContents /* = true*/) { 56 | auto output = make_unique(); 57 | output->reserve(input->size()); // allocate the right memory 58 | 59 | if (input == nullptr || input->size() == 0) { 60 | 61 | #if !SUPPRESSDEBUGLOG 62 | ESP_LOGD(LOGTAG, "[DEBUG] UnsignedCharVectorToString called with null data!\n"); 63 | #endif 64 | 65 | return output; 66 | } 67 | 68 | if (input == nullptr) 69 | return output; 70 | 71 | if (emptyContents) { 72 | while (input->size() > 0) { 73 | output->push_back( input->at(0) ); 74 | input->erase(input->begin()); 75 | } 76 | } 77 | else { 78 | for (int i=0; isize(); i++) { 79 | output->push_back( input->at(i) ); 80 | } 81 | } 82 | 83 | // Resize input 84 | input->shrink_to_fit(); 85 | 86 | return output; 87 | } 88 | 89 | unique_ptr> BriandNet::RawInsecureRequest(const string& host, const short& port, unique_ptr>& content, bool emptyContents /* = true*/) { 90 | auto output = make_unique>(); 91 | output->reserve(1024); // min. 1KB reserved 92 | 93 | if (content == nullptr || content->size() == 0) { 94 | 95 | #if !SUPPRESSDEBUGLOG 96 | ESP_LOGD(LOGTAG, "[DEBUG] RawInsecureRequest called with null data!\n"); 97 | #endif 98 | 99 | return output; 100 | } 101 | 102 | auto client = make_unique(); 103 | 104 | // Set parameters 105 | client->SetVerbose(false); 106 | client->SetTimeout(NET_CONNECT_TIMEOUT_S, NET_IO_TIMEOUT_S); 107 | 108 | // Connect 109 | if ( !client->Connect(host.c_str(), port) ) { 110 | ESP_LOGW(LOGTAG, "[ERR] Failed to connect\n"); 111 | return output; 112 | } 113 | 114 | #if !SUPPRESSDEBUGLOG 115 | ESP_LOGD(LOGTAG, "[DEBUG] Connected.\n"); 116 | #endif 117 | 118 | // Write request 119 | if ( !client->WriteData(content) ) { 120 | ESP_LOGW(LOGTAG, "[ERR] Failed to send data\n"); 121 | return output; 122 | } 123 | 124 | if (emptyContents) 125 | content->clear(); 126 | 127 | // Wait response until timeout reached 128 | 129 | #if !SUPPRESSDEBUGLOG 130 | ESP_LOGD(LOGTAG, "[DEBUG] Request sent.\n"); 131 | ESP_LOGD(LOGTAG, "[DEBUG] Waiting response"); 132 | #endif 133 | 134 | // Response 135 | output = client->ReadData(false); 136 | 137 | #if !SUPPRESSDEBUGLOG 138 | ESP_LOGD(LOGTAG, "[DEBUG] Got response of %d bytes.\n", output->size()); 139 | #endif 140 | 141 | client->Disconnect(); 142 | 143 | client.reset(); // Release now please, I need RAM! 144 | 145 | return std::move(output); 146 | } 147 | 148 | unique_ptr> BriandNet::RawSecureRequest(const unique_ptr& client, unique_ptr>& content, bool emptyContents /* = true*/, bool closeConnection /* = false*/, bool expectResponse /* = true */) { 149 | auto output = make_unique>(); 150 | output->reserve(512); // min 512KB 151 | 152 | if (content == nullptr || content->size() == 0) { 153 | 154 | #if !SUPPRESSDEBUGLOG 155 | ESP_LOGD(LOGTAG, "[DEBUG] RawSecureRequest called with null data!\n"); 156 | #endif 157 | 158 | return output; 159 | } 160 | 161 | // Write request 162 | 163 | client->WriteData(content); 164 | 165 | if (emptyContents) 166 | content->clear(); 167 | 168 | // If response expected 169 | if (expectResponse) { 170 | // Wait response until timeout reached 171 | // Read response 172 | output = client->ReadData(); 173 | 174 | #if !SUPPRESSDEBUGLOG 175 | ESP_LOGD(LOGTAG, "[DEBUG] Got response of %d bytes.\n", output->size()); 176 | #endif 177 | 178 | if (client->IsConnected() && closeConnection) 179 | client->Disconnect(); 180 | } 181 | 182 | return std::move(output); 183 | } 184 | 185 | unique_ptr> BriandNet::RawSecureRequest(const string& host, const short& port, unique_ptr>& content, bool emptyContents /* = true*/, const unique_ptr& pemCAcert /*= nullptr*/, const unique_ptr>& derCAcert /*= nullptr*/) { 186 | auto output = make_unique>(); 187 | 188 | if (content == nullptr || content->size() == 0) { 189 | 190 | #if !SUPPRESSDEBUGLOG 191 | ESP_LOGD(LOGTAG, "[DEBUG] RawSecureRequest called with null data!\n"); 192 | #endif 193 | 194 | return output; 195 | } 196 | 197 | auto client = make_unique(); 198 | 199 | // Set parameters 200 | client->SetVerbose(false); 201 | client->SetTimeout(NET_CONNECT_TIMEOUT_S, NET_IO_TIMEOUT_S); 202 | 203 | if (pemCAcert != nullptr) { 204 | client->SetCACertificateChainPEM(*pemCAcert.get()); 205 | } 206 | else if (derCAcert != nullptr) { 207 | client->AddCACertificateToChainDER(*derCAcert.get()); 208 | } 209 | else { 210 | 211 | #if !SUPPRESSDEBUGLOG 212 | ESP_LOGD(LOGTAG, "[DEBUG] Insecure mode (no PEM/DER CA certificate).\n"); 213 | #endif 214 | 215 | } 216 | 217 | // Connect 218 | 219 | if ( !client->Connect(host, port) ) { 220 | ESP_LOGW(LOGTAG, "[ERR] Failed to connect\n"); 221 | return output; 222 | } 223 | 224 | #if !SUPPRESSDEBUGLOG 225 | ESP_LOGD(LOGTAG, "[DEBUG] Connected.\n"); 226 | #endif 227 | 228 | // Write request 229 | client->WriteData(content); 230 | 231 | 232 | if (emptyContents) 233 | content->clear(); 234 | 235 | // Wait response until timeout reached 236 | 237 | #if !SUPPRESSDEBUGLOG 238 | ESP_LOGD(LOGTAG, "[DEBUG] Request sent.\n"); 239 | ESP_LOGD(LOGTAG, "[DEBUG] Waiting response\n"); 240 | #endif 241 | 242 | // Response ready! 243 | output = client->ReadData(); 244 | 245 | #if !SUPPRESSDEBUGLOG 246 | ESP_LOGD(LOGTAG, "[DEBUG] Got response of %d bytes.\n", output->size()); 247 | #endif 248 | 249 | if (client->IsConnected()) 250 | client->Disconnect(); 251 | 252 | client.reset(); // Release now please, I need RAM! 253 | 254 | return std::move(output); 255 | } 256 | 257 | unique_ptr BriandNet::HttpsGet(const string& host, const short& port, const string& path, short& httpReturnCode, const string& agent /* = "empty"*/, const bool& returnBodyOnly /* = false*/, const unique_ptr& pemCAcert /*= nullptr*/, const unique_ptr>& derCAcert /*= nullptr*/) { 258 | 259 | #if !SUPPRESSDEBUGLOG 260 | ESP_LOGD(LOGTAG, "[DEBUG] HttpsGet called to https://%s:%d%s\n", host.c_str(), port, path.c_str()); 261 | #endif 262 | 263 | // Prepare request 264 | 265 | auto request = make_unique(); 266 | request->append("GET " + path + " HTTP/1.1\r\n"); 267 | request->append("Host: " + host + "\r\n"); 268 | request->append("User-Agent: " + agent); 269 | request->append("\r\n"); 270 | request->append("Connection: close\r\n"); 271 | request->append("\r\n"); 272 | 273 | auto contents = StringToUnsignedCharVector(request, true); 274 | request.reset(); 275 | 276 | #if !SUPPRESSDEBUGLOG 277 | ESP_LOGD(LOGTAG, "[DEBUG] HttpsGet sending raw request.\n"); 278 | #endif 279 | 280 | auto response = RawSecureRequest(host, port, contents, true, pemCAcert, derCAcert); 281 | 282 | if (response->size() > 0) { 283 | // Success 284 | 285 | #if !SUPPRESSDEBUGLOG 286 | ESP_LOGD(LOGTAG, "[DEBUG] HttpsGet success.\n"); 287 | #endif 288 | 289 | // Convert to string 290 | auto responseContent = UnsignedCharVectorToString(response, true); 291 | 292 | // Parse header to get httpCode 293 | // HTTP/1.1 XXX OK 294 | // 3 digit after space 295 | httpReturnCode = stoi( responseContent->substr(responseContent->find(" ") + 1, 3 ) ); 296 | 297 | if (returnBodyOnly) { 298 | // Get the body without headers 299 | // from double \r\n to the end 300 | responseContent->erase(0, responseContent->find("\r\n\r\n")+4 ); 301 | } 302 | 303 | return responseContent; 304 | } 305 | else { 306 | 307 | #if !SUPPRESSDEBUGLOG 308 | ESP_LOGD(LOGTAG, "[DEBUG] HttpsGet failed.\n"); 309 | #endif 310 | 311 | return nullptr; 312 | } 313 | } 314 | 315 | unique_ptr BriandNet::HttpInsecureGet(const string& host, const short& port, const string& path, short& httpReturnCode, const string& agent /* = "empty"*/, const bool& returnBodyOnly /* = false*/) { 316 | 317 | #if !SUPPRESSDEBUGLOG 318 | ESP_LOGD(LOGTAG, "[DEBUG] HttpInsecureGet called to http://%s:%d%s\n", host.c_str(), port, path.c_str()); 319 | #endif 320 | 321 | // Prepare request 322 | 323 | auto request = make_unique(); 324 | request->append("GET " + path + " HTTP/1.1\r\n"); 325 | request->append("Host: " + host + "\r\n"); 326 | request->append("User-Agent: " + agent); 327 | request->append("\r\n"); 328 | request->append("Connection: close\r\n"); 329 | request->append("\r\n"); 330 | 331 | auto contents = StringToUnsignedCharVector(request, true); 332 | 333 | #if !SUPPRESSDEBUGLOG 334 | ESP_LOGD(LOGTAG, "[DEBUG] HttpInsecureGet sending raw request.\n"); 335 | #endif 336 | 337 | auto response = RawInsecureRequest(host, port, contents, true); 338 | 339 | if (response->size() > 0) { 340 | // Success 341 | 342 | #if !SUPPRESSDEBUGLOG 343 | ESP_LOGD(LOGTAG, "[DEBUG] HttpInsecureGet success.\n"); 344 | #endif 345 | 346 | // Convert to string 347 | auto responseContent = UnsignedCharVectorToString(response, true); 348 | 349 | // Parse header to get httpCode 350 | // HTTP/1.1 XXX OK 351 | // 3 digit after space 352 | size_t httpStatusPos = responseContent->find(" "); 353 | if (httpStatusPos != string::npos) { 354 | string httpStatusStr = responseContent->substr(httpStatusPos + 1, 3 ); 355 | if (httpStatusStr.size() > 0) 356 | httpReturnCode = stoi( httpStatusStr ); 357 | } 358 | 359 | if (returnBodyOnly) { 360 | // Get the body without headers 361 | // from double \r\n to the end 362 | responseContent->erase(0, responseContent->find("\r\n\r\n")+4 ); 363 | } 364 | 365 | return responseContent; 366 | } 367 | else { 368 | 369 | #if !SUPPRESSDEBUGLOG 370 | ESP_LOGD(LOGTAG, "[DEBUG] HttpInsecureGet failed.\n"); 371 | #endif 372 | 373 | return nullptr; 374 | } 375 | } 376 | 377 | } -------------------------------------------------------------------------------- /src/BriandTorCircuitsManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandTorCircuitsManager.hxx" 20 | #include "BriandUtils.hxx" 21 | 22 | using namespace std; 23 | 24 | namespace Briand 25 | { 26 | const char* BriandTorCircuitsManager::LOGTAG = "briandcircmgr"; 27 | 28 | unique_ptr[]> BriandTorCircuitsManager::CIRCUITS = nullptr; 29 | unsigned short BriandTorCircuitsManager::CIRCUIT_POOL_SIZE = 3; 30 | unsigned short BriandTorCircuitsManager::CIRCUIT_MAX_TIME = 900; 31 | unsigned short BriandTorCircuitsManager::CIRCUIT_MAX_REQUESTS = 15; 32 | bool BriandTorCircuitsManager::isStopped = true; 33 | 34 | BriandTorCircuitsManager::BriandTorCircuitsManager() : BriandTorCircuitsManager(3, 15*60, 15) { 35 | } 36 | 37 | BriandTorCircuitsManager::BriandTorCircuitsManager(const unsigned short& poolSize, const unsigned short& maxTime, const unsigned short& maxRequests) { 38 | this->CIRCUIT_POOL_SIZE = poolSize; 39 | this->CIRCUIT_MAX_TIME = maxTime; 40 | this->CIRCUIT_MAX_REQUESTS = maxRequests; 41 | this->CIRCUITS = make_unique[]>(this->CIRCUIT_POOL_SIZE); 42 | 43 | // Allocate all thread safe wrappers 44 | for (unsigned short i=0; iCIRCUIT_POOL_SIZE; i++) 45 | this->CIRCUITS[i] = make_unique(); 46 | 47 | this->CIRCUIT_LAST_USED = -1; 48 | this->isStopped = true; 49 | } 50 | 51 | BriandTorCircuitsManager::~BriandTorCircuitsManager() { 52 | this->Stop(); 53 | this->CIRCUITS.reset(); 54 | } 55 | 56 | void BriandTorCircuitsManager::Start() { 57 | // If not empty, clear out the current circuit pool (useful if Stop() not called and want to re-Start the manager) 58 | #if !SUPPRESSDEBUGLOG 59 | ESP_LOGD(LOGTAG, "Stopping old instances.\n"); 60 | #endif 61 | 62 | this->Stop(); 63 | 64 | #if !SUPPRESSDEBUGLOG 65 | ESP_LOGD(LOGTAG, "Starting circuits.\n"); 66 | #endif 67 | 68 | // Create a task to periodically check circuit instances situation 69 | auto pcfg = esp_pthread_get_default_config(); 70 | pcfg.thread_name = "MgrInst"; 71 | pcfg.stack_size = STACK_MgrInst; 72 | pcfg.prio = 500; 73 | esp_pthread_set_cfg(&pcfg); 74 | std::thread t(CircuitsTaskSingle, (void*)NULL); 75 | 76 | this->isStopped = false; 77 | 78 | // Check correct thread creation 79 | if (!t.joinable()) { 80 | ESP_LOGE(LOGTAG, "[ERR] CircuitsManager Start(): PThread could not be created. Please retry.\n"); 81 | this->isStopped = true; 82 | } 83 | else { 84 | t.detach(); 85 | } 86 | } 87 | 88 | /*static*/ void BriandTorCircuitsManager::CircuitsTaskSingle(void* noparam) { 89 | // PTHREAD IMPLEMENTATION 90 | while(!BriandTorCircuitsManager::isStopped) { 91 | 92 | // If rebulding cache do not run. 93 | if (BriandTorRelaySearcher::CACHE_REBUILDING) { 94 | vTaskDelay(2000 / portTICK_PERIOD_MS); 95 | continue; 96 | } 97 | 98 | #if !SUPPRESSDEBUGLOG 99 | ESP_LOGD(LOGTAG, "[DEBUG] CircuitsManager main task invoked, checking for instances to be created.\n"); 100 | #endif 101 | 102 | // Check if there are the number of needed circuits built, if not add the needed 103 | for (unsigned short i = 0; i < BriandTorCircuitsManager::CIRCUIT_POOL_SIZE; i++) { 104 | // A new circuit to be instanced? 105 | if (BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance == nullptr) { 106 | 107 | #if !SUPPRESSDEBUGLOG 108 | ESP_LOGD(LOGTAG, "[DEBUG] Adding a new circuit to pool as #%hu.\n", i); 109 | #endif 110 | 111 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance = make_unique(); 112 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->internalID = i; 113 | } 114 | 115 | // Lock circuit 116 | unique_lock lock(BriandTorCircuitsManager::CIRCUITS[i]->CircuitMutex); 117 | 118 | // Circuit to build? 119 | if ( 120 | !BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::BUILT) && 121 | !BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::BUILDING)) 122 | { 123 | // A new circuit to be built 124 | #if !SUPPRESSDEBUGLOG 125 | ESP_LOGD(LOGTAG, "[DEBUG] Circuit #%hu needs to be built, building.\n", i); 126 | #endif 127 | 128 | // Here circuit is not built nor in creating, so build it. 129 | if (!BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->BuildCircuit(false)) { 130 | // If fails, reset and terminate. 131 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance.reset(); 132 | } 133 | } 134 | // A circuit that should be deleted? 135 | else if (BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::CLOSED)) { 136 | 137 | #if !SUPPRESSDEBUGLOG 138 | ESP_LOGD(LOGTAG, "[DEBUG] Circuit #%hu is closed, removing from pool.\n", i); 139 | #endif 140 | 141 | // Reset the pointer 142 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance.reset(); 143 | } 144 | // Operative circuit? 145 | else if(BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::BUILT)) { 146 | if (BriandUtils::GetUnixTime() >= BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->GetCreatedOn() + BriandTorCircuitsManager::CIRCUIT_MAX_TIME) { 147 | // The circuit should be closed for elapsed time 148 | 149 | #if !SUPPRESSDEBUGLOG 150 | ESP_LOGD(LOGTAG, "[DEBUG] Circuit #%hu has reached maximum life time, sending destroy.\n", i); 151 | #endif 152 | 153 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->TearDown(Briand::BriandTorDestroyReason::FINISHED); 154 | } 155 | else if (BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->GetCurrentStreamID() >= BriandTorCircuitsManager::CIRCUIT_MAX_REQUESTS) { 156 | // The circuit should be closed for maximum requests 157 | 158 | #if !SUPPRESSDEBUGLOG 159 | ESP_LOGD(LOGTAG, "[DEBUG] Circuit #%hu has reached maximum requests, sending destroy.\n", i); 160 | #endif 161 | 162 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->TearDown(Briand::BriandTorDestroyReason::FINISHED); 163 | } 164 | else if (!BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::STREAMING)) { 165 | // No problems 166 | // Send a PADDING to keep alive! 167 | 168 | #if !SUPPRESSDEBUGLOG 169 | ESP_LOGD(LOGTAG, "[DEBUG] Circuit #%hu is alive and not busy, sending PADDING.\n", i); 170 | #endif 171 | 172 | BriandTorCircuitsManager::CIRCUITS[i]->CircuitInstance->SendPadding(); 173 | } 174 | } 175 | } 176 | 177 | // Wait before next execution. 178 | vTaskDelay(BriandTorCircuitsManager::TASK_WAIT_BEFORE_NEXT / portTICK_PERIOD_MS); 179 | } 180 | 181 | #if !SUPPRESSDEBUGLOG 182 | ESP_LOGD(LOGTAG, "[DEBUG] Stopping CircuitsManager main task.\n"); 183 | #endif 184 | 185 | } 186 | 187 | void BriandTorCircuitsManager::Stop() { 188 | // Kill all circuits, check are not doing work before killing 189 | 190 | // This grants no instances are created by instance task while closing the existing ones 191 | this->isStopped = true; 192 | 193 | unsigned short queue; 194 | do { 195 | queue = this->CIRCUIT_POOL_SIZE; 196 | 197 | for (unsigned short i=0; iCIRCUIT_POOL_SIZE; i++) { 198 | // Lock the circuit 199 | unique_lock lock(this->CIRCUITS[i]->CircuitMutex); 200 | 201 | if (this->CIRCUITS[i]->CircuitInstance != nullptr) { 202 | this->CIRCUITS[i]->CircuitInstance.reset(); 203 | } 204 | else if (this->CIRCUITS[i]->CircuitInstance == nullptr) { 205 | queue--; 206 | } 207 | } 208 | 209 | // Little delay to prevent wdt reset on ESP32 210 | vTaskDelay(200 / portTICK_PERIOD_MS); 211 | } while (queue > 0); 212 | } 213 | 214 | BriandTorThreadSafeCircuit* BriandTorCircuitsManager::GetCircuit() { 215 | unsigned short testedCircuits = (this->CIRCUIT_LAST_USED + 1) % this->CIRCUIT_POOL_SIZE; 216 | 217 | do { 218 | // Evaluate all circuits, including the last used if it is the only one available 219 | 220 | if (BriandTorCircuitsManager::CIRCUITS[testedCircuits]->CircuitInstance != nullptr) { 221 | auto& circuit = BriandTorCircuitsManager::CIRCUITS[testedCircuits]->CircuitInstance; 222 | if (circuit->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::BUILT) && 223 | !circuit->StatusGetFlag(BriandTorCircuit::CircuitStatusFlag::STREAMING)) 224 | { 225 | this->CIRCUIT_LAST_USED = circuit->internalID; 226 | return BriandTorCircuitsManager::CIRCUITS[testedCircuits].get(); 227 | } 228 | } 229 | 230 | testedCircuits = (testedCircuits + 1) % this->CIRCUIT_POOL_SIZE; 231 | 232 | } while (testedCircuits != ((this->CIRCUIT_LAST_USED + 1) % this->CIRCUIT_POOL_SIZE)); 233 | 234 | return nullptr; 235 | } 236 | 237 | bool BriandTorCircuitsManager::IsStarted() { 238 | return !this->isStopped; 239 | } 240 | 241 | void BriandTorCircuitsManager::PrintCircuitsInfo() { 242 | printf("#\tCircID\t\tStatus\t\t\t\t\tPaddings\tCreatedOn\tDescription\n"); 243 | for (unsigned short i=0; iCIRCUIT_POOL_SIZE; i++) { 244 | printf("%u\t", i); 245 | if (this->CIRCUITS[i]->CircuitInstance == nullptr) { 246 | printf("0x00000000\tNONE\t\t\t\t\t%08lu\t%08lu\tNot instanced\n", 0L, 0L); 247 | } 248 | else { 249 | auto& circuit = this->CIRCUITS[i]->CircuitInstance; 250 | 251 | printf("0x%08X\t", circuit->GetCircID()); 252 | 253 | string circuitStatus = circuit->StatusGetString(); 254 | 255 | /* 256 | Prepend mutex lock information: 257 | try to lock, if success then the circuit were free of locks and could be unlocked. 258 | If not, then a thread is currently using mutex. Warning: this can be done because 259 | calling thread should be a non-blocking thread (ex. statistical/prompt etc.). If would 260 | be the same thread then this call will throw system_error. That's why of try-catch 261 | */ 262 | try { 263 | if (this->CIRCUITS[i]->CircuitMutex.try_lock()) { 264 | this->CIRCUITS[i]->CircuitMutex.unlock(); 265 | // nothing else to do 266 | } 267 | else { 268 | circuitStatus = "LCK," + circuitStatus; 269 | } 270 | } catch(...) { 271 | ESP_LOGE(LOGTAG, "[WARN] try_lock exception: do not call PrintCircuitsInfo() from a circuit-blocking thread!\n"); 272 | } 273 | 274 | // Indent 275 | while(circuitStatus.length() < 40) circuitStatus.push_back(' '); 276 | 277 | printf("%s", circuitStatus.c_str()); 278 | 279 | printf("%08lu\t", circuit->GetSentPadding()); 280 | printf("%08lu\t", circuit->GetCreatedOn()); 281 | 282 | printf("You, "); 283 | 284 | if (circuit->guardNode != nullptr && circuit->guardNode->nickname != nullptr) 285 | printf("%s, ", circuit->guardNode->nickname->c_str() ); 286 | 287 | if (circuit->middleNode != nullptr && circuit->middleNode->nickname != nullptr) 288 | printf("%s, ", circuit->middleNode->nickname->c_str() ); 289 | 290 | if (circuit->exitNode != nullptr && circuit->exitNode->nickname != nullptr) { 291 | printf("%s, ", circuit->exitNode->nickname->c_str() ); 292 | printf("THE WEB"); 293 | } 294 | 295 | printf("\n"); 296 | } 297 | } 298 | } 299 | 300 | } -------------------------------------------------------------------------------- /src/BriandTorDirAuthority.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Briand TorEsp32 https://github.com/briand-hub/toresp32 4 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include "BriandTorDirAuthority.hxx" 21 | 22 | // Static member for the last responding authority 23 | unsigned short TOR_DIR_LAST_USED = 0x0000; 24 | 25 | /** retrieves the best directory for speed/connection and sets to TOR_DIR_LAST_USED */ 26 | void briand_find_best_dir() { 27 | printf("[INFO] Finding best authority directory, may take some time.\n"); 28 | 29 | auto minOperTime = INT64_MAX; 30 | unsigned short minOperDir = TOR_DIR_AUTHORITIES_NUMBER + 1; 31 | 32 | for (unsigned short i = 0; i(); 39 | client->SetReceivingBufferSize(512); 40 | // Use small timeouts 41 | client->SetTimeout(15, 15); 42 | client->SetVerbose(false); 43 | 44 | if (!client->Connect(TOR_DIR_AUTHORITIES[i].host, TOR_DIR_AUTHORITIES[i].port)) { 45 | // sure not this dir 46 | printf("connect failed.\n"); 47 | continue; 48 | } 49 | 50 | auto request = make_unique(); 51 | request->append("GET /tor/server/fp/" + string(TOR_DIR_AUTHORITIES[i].fingerprint) + " HTTP/1.1\r\n"); 52 | request->append("Connection: close\r\n"); 53 | request->append("\r\n"); 54 | 55 | auto requestV = Briand::BriandNet::StringToUnsignedCharVector(request, true); 56 | if (!client->WriteData(requestV)) { 57 | // sure not this dir 58 | printf("request failed.\n"); 59 | client->Disconnect(); 60 | continue; 61 | } 62 | 63 | unique_ptr> data = nullptr; 64 | size_t bytes = 0; 65 | do { 66 | data = client->ReadData(true); 67 | if (data != nullptr) bytes += data->size(); 68 | } while (data != nullptr && data->size() > 0); 69 | 70 | client->Disconnect(); 71 | 72 | if (bytes > 0) { 73 | auto requiredTime = esp_timer_get_time() - startTime; 74 | if (requiredTime < minOperTime) { 75 | minOperTime = requiredTime; 76 | minOperDir = i; 77 | } 78 | printf("%zu bytes downloaded in %lld ms (%.0f B/s)\n", bytes, requiredTime/1000, bytes/(requiredTime/1000.0)); 79 | } 80 | else { 81 | printf("download failed.\n"); 82 | } 83 | } 84 | 85 | if (minOperDir == TOR_DIR_AUTHORITIES_NUMBER + 1) { 86 | printf("[INFO] Finding best authoriry directory finished with failure.\n"); 87 | TOR_DIR_LAST_USED = 0; 88 | } 89 | else { 90 | printf("[INFO] Finding best authoriry directory finished: %s (%s) is best with %lld milliseconds.\n", TOR_DIR_AUTHORITIES[minOperDir].nickname, TOR_DIR_AUTHORITIES[minOperDir].host, (minOperTime/1000)); 91 | // Save the best result 92 | TOR_DIR_LAST_USED = minOperDir; 93 | } 94 | } -------------------------------------------------------------------------------- /src/BriandTorStatistics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandTorStatistics.hxx" 20 | 21 | using namespace std; 22 | 23 | namespace Briand { 24 | 25 | unsigned int BriandTorStatistics::STAT_NUM_PROTOCOL_ERR = 0; 26 | unsigned int BriandTorStatistics::STAT_NUM_EXIT_POLICY_ERR = 0; 27 | unsigned int BriandTorStatistics::STAT_NUM_FINISHED = 0; 28 | unsigned int BriandTorStatistics::STAT_NUM_RECV_PADDINGS = 0; 29 | unsigned int BriandTorStatistics::STAT_NUM_CACHE_GUARD_MISS = 0; 30 | unsigned int BriandTorStatistics::STAT_NUM_CACHE_MIDDLE_MISS = 0; 31 | unsigned int BriandTorStatistics::STAT_NUM_CACHE_EXIT_MISS = 0; 32 | unsigned int BriandTorStatistics::STAT_NUM_GUARD_CONN_ERR = 0; 33 | unsigned int BriandTorStatistics::STAT_NUM_DESCRIPTOR_FETCH_ERR = 0; 34 | unsigned int BriandTorStatistics::STAT_NUM_CREATE2_FAIL = 0; 35 | unsigned int BriandTorStatistics::STAT_NUM_EXTEND2_FAIL = 0; 36 | unsigned int BriandTorStatistics::STAT_DESCRIPTORS_N = 0; 37 | unsigned int BriandTorStatistics::STAT_DESCRIPTORS_TIME_AVG = 0; 38 | unsigned int BriandTorStatistics::STAT_BUILT_N = 0; 39 | unsigned int BriandTorStatistics::STAT_BUILD_TIME_AVG = 0; 40 | unsigned int BriandTorStatistics::STAT_NUM_CACHE_SAME_IP_DROP = 0; 41 | unsigned int BriandTorStatistics::STAT_NUM_CACHE_EXIT_PORT_DROP = 0; 42 | unsigned int BriandTorStatistics::STAT_TOR_SEND_TIME_AVG = 0; 43 | unsigned int BriandTorStatistics::STAT_TOR_SEND_N = 0; 44 | unsigned int BriandTorStatistics::STAT_TOR_RECV_TIME_AVG = 0; 45 | unsigned int BriandTorStatistics::STAT_TOR_RECV_N = 0; 46 | unsigned int BriandTorStatistics::STAT_CACHE_BUILD_TIME = 0; 47 | 48 | BriandTorStatistics::BriandTorStatistics() { } 49 | 50 | BriandTorStatistics::~BriandTorStatistics() { } 51 | 52 | void BriandTorStatistics::SaveStatistic(const unique_ptr& cell) { 53 | if (cell->GetCommand() == BriandTorCellCommand::PADDING) { 54 | BriandTorStatistics::STAT_NUM_RECV_PADDINGS++; 55 | } 56 | else if (cell->GetCommand() == BriandTorCellCommand::DESTROY) { 57 | SaveStatistic(static_cast(cell->GetPayload()->at(0))); 58 | } 59 | else if (cell->GetCommand() == BriandTorCellCommand::RELAY && cell->GetRelayCommand() == BriandTorCellRelayCommand::RELAY_TRUNCATED) { 60 | SaveStatistic(static_cast(cell->GetPayload()->at(0))); 61 | } 62 | else if (cell->GetCommand() == BriandTorCellCommand::RELAY && cell->GetRelayCommand() == BriandTorCellRelayCommand::RELAY_END) { 63 | SaveStatistic(static_cast(cell->GetPayload()->at(0))); 64 | } 65 | } 66 | 67 | void BriandTorStatistics::SaveStatistic(const BriandTorDestroyReason& reason) { 68 | if (reason == BriandTorDestroyReason::PROTOCOL) { 69 | BriandTorStatistics::STAT_NUM_PROTOCOL_ERR++; 70 | } 71 | } 72 | 73 | void BriandTorStatistics::SaveStatistic(const BriandTorRelayEndReason& reason) { 74 | if (reason == BriandTorRelayEndReason::REASON_TORPROTOCOL) { 75 | BriandTorStatistics::STAT_NUM_PROTOCOL_ERR++; 76 | } 77 | else if (reason == BriandTorRelayEndReason::REASON_EXITPOLICY) { 78 | BriandTorStatistics::STAT_NUM_EXIT_POLICY_ERR++; 79 | } 80 | else if (reason == BriandTorRelayEndReason::REASON_DONE) { 81 | BriandTorStatistics::STAT_NUM_FINISHED++; 82 | } 83 | } 84 | 85 | void BriandTorStatistics::Print() { 86 | printf("------ SATISTICS -------\n"); 87 | 88 | printf("No. of normal stream finish: %u\n", BriandTorStatistics::STAT_NUM_FINISHED); 89 | printf("No. of received paddings: %u\n", BriandTorStatistics::STAT_NUM_RECV_PADDINGS); 90 | printf("No. of exit policy errors: %u\n", BriandTorStatistics::STAT_NUM_EXIT_POLICY_ERR); 91 | printf("No. of protocol errors: %u\n", BriandTorStatistics::STAT_NUM_PROTOCOL_ERR); 92 | printf("Cache build time (s): %u\n", BriandTorStatistics::STAT_CACHE_BUILD_TIME); 93 | printf("No. of cache guard fail: %u\n", BriandTorStatistics::STAT_NUM_CACHE_GUARD_MISS); 94 | printf("No. of cache middle fail: %u\n", BriandTorStatistics::STAT_NUM_CACHE_MIDDLE_MISS); 95 | printf("No. of cache exit fail: %u\n", BriandTorStatistics::STAT_NUM_CACHE_EXIT_MISS); 96 | printf("No. of cache fail for same family ip: %u\n", BriandTorStatistics::STAT_NUM_CACHE_SAME_IP_DROP); 97 | printf("No. of cache fail for port settings requirements: %u\n", BriandTorStatistics::STAT_NUM_CACHE_EXIT_PORT_DROP); 98 | printf("No. of failed connections to guard: %u\n", BriandTorStatistics::STAT_NUM_GUARD_CONN_ERR); 99 | printf("No. of failed descriptor fetch: %u\n", BriandTorStatistics::STAT_NUM_DESCRIPTOR_FETCH_ERR); 100 | printf("Avg time to fetch descriptors (ms): %u (based on %u fetched)\n", BriandTorStatistics::STAT_DESCRIPTORS_TIME_AVG, BriandTorStatistics::STAT_DESCRIPTORS_N); 101 | printf("No. of failed create2: %u\n", BriandTorStatistics::STAT_NUM_CREATE2_FAIL); 102 | printf("No. of failed extend2: %u\n", BriandTorStatistics::STAT_NUM_EXTEND2_FAIL); 103 | printf("Avg time to build a circuit (ms): %u (based on %u built circuits)\n", BriandTorStatistics::STAT_BUILD_TIME_AVG, BriandTorStatistics::STAT_BUILT_N); 104 | printf("Avg time Tor stream recv (ms): %u (based on %u stream cells)\n", BriandTorStatistics::STAT_TOR_RECV_TIME_AVG, BriandTorStatistics::STAT_TOR_RECV_N); 105 | printf("Avg time Tor stream send (ms): %u (based on %u stream cells)\n", BriandTorStatistics::STAT_TOR_SEND_TIME_AVG, BriandTorStatistics::STAT_TOR_SEND_N); 106 | 107 | printf("------------------------\n"); 108 | } 109 | 110 | } -------------------------------------------------------------------------------- /src/BriandUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Briand TorEsp32 https://github.com/briand-hub/toresp32 3 | Copyright (C) 2021 Author: briand (https://github.com/briand-hub) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "BriandUtils.hxx" 20 | 21 | #include "BriandDefines.hxx" 22 | #include "BriandTorDefinitions.hxx" 23 | #include "BriandNet.hxx" 24 | 25 | using namespace std; 26 | 27 | namespace Briand 28 | { 29 | const char* BriandUtils::LOGTAG = "briandutils"; 30 | 31 | unsigned char BriandUtils::GetRandomByte() { 32 | 33 | // NOT working in ESP: 34 | 35 | //default_random_engine generator; 36 | //uniform_int_distribution distribution(0x00, 0xFF); 37 | //return static_cast( distribution(generator) % 0x100 ); 38 | 39 | // Better implementation, best if wifi is enabled 40 | // return static_cast( esp_random() ); 41 | return static_cast( esp_random() % 0x100 ); 42 | } 43 | 44 | unique_ptr BriandUtils::GetRandomMAC() { 45 | auto mac = make_unique(6); 46 | 47 | mac[0] = GetRandomByte(); 48 | mac[1] = GetRandomByte(); 49 | mac[2] = GetRandomByte(); 50 | mac[3] = GetRandomByte(); 51 | mac[4] = GetRandomByte(); 52 | mac[5] = GetRandomByte(); 53 | 54 | return mac; 55 | } 56 | 57 | unique_ptr BriandUtils::GetRandomHostName() { 58 | auto temp = make_unique(WIFI_HOSTNAME_LEN + 1); 59 | unsigned char counter = 0; 60 | 61 | // Use only alphanumeric ascii-chars [a-z][A-Z][0-9] 62 | while (counter < WIFI_HOSTNAME_LEN) { 63 | unsigned char randomChar = GetRandomByte(); 64 | if ( 65 | (randomChar >= 0x30 && randomChar <= 0x39) || 66 | (randomChar >= 0x41 && randomChar <= 0x5A) || 67 | (randomChar >= 0x61 && randomChar <= 0x7A) 68 | ) { 69 | temp[counter] = randomChar; 70 | counter++; 71 | } 72 | } 73 | 74 | temp [WIFI_HOSTNAME_LEN] = '\0'; // null terminate string! 75 | 76 | return move(temp); 77 | } 78 | 79 | unique_ptr BriandUtils::GetRandomSSID() { 80 | auto temp = make_unique(WIFI_AP_SSID_LEN + 1); 81 | unsigned char counter = 0; 82 | 83 | // Use only alphanumeric ascii-chars [a-z][A-Z][0-9] 84 | while (counter < WIFI_AP_SSID_LEN) { 85 | unsigned char randomChar = GetRandomByte(); 86 | if ( 87 | (randomChar >= 0x30 && randomChar <= 0x39) || 88 | (randomChar >= 0x41 && randomChar <= 0x5A) || 89 | (randomChar >= 0x61 && randomChar <= 0x7A) 90 | ) { 91 | temp[counter] = randomChar; 92 | counter++; 93 | } 94 | } 95 | 96 | temp [WIFI_AP_SSID_LEN] = '\0'; // null terminate string! 97 | 98 | return move(temp); 99 | } 100 | 101 | unique_ptr BriandUtils::GetRandomPassword(int length) { 102 | auto temp = make_unique(length + 1); 103 | unsigned char counter = 0; 104 | 105 | // Use useful ASCII chars 106 | while (counter < length) { 107 | unsigned char randomChar = GetRandomByte(); 108 | if (randomChar != 0x60 && (randomChar >= 0x21 && randomChar <= 0x7E)) { 109 | temp[counter] = randomChar; 110 | counter++; 111 | } 112 | } 113 | 114 | temp[length] = '\0'; // null terminate string! 115 | 116 | return move(temp); 117 | } 118 | 119 | string BriandUtils::BriandTorRelayFlagsToString(unsigned short flagMask, const string& prepend /* = ""*/, const string& separator /* = " "*/) { 120 | string output(""); 121 | 122 | if (flagMask & Briand::BriandTorRelayFlag::AUTHORITY) { 123 | output.append(prepend); 124 | output.append("Authority"); 125 | output.append(separator); 126 | } 127 | if (flagMask & Briand::BriandTorRelayFlag::BADEXIT) { 128 | output.append(prepend); 129 | output.append("BadExit"); 130 | output.append(separator); 131 | } 132 | if (flagMask & Briand::BriandTorRelayFlag::EXIT) { 133 | output.append(prepend); 134 | output.append("Exit"); 135 | output.append(separator); 136 | } 137 | if (flagMask & Briand::BriandTorRelayFlag::FAST) { 138 | output.append(prepend); 139 | output.append("Fast"); 140 | output.append(separator); 141 | } 142 | if (flagMask & Briand::BriandTorRelayFlag::GUARD) { 143 | output.append(prepend); 144 | output.append("Guard"); 145 | output.append(separator); 146 | } 147 | if (flagMask & Briand::BriandTorRelayFlag::HSDIR) { 148 | output.append(prepend); 149 | output.append("HSDir"); 150 | output.append(separator); 151 | } 152 | if (flagMask & Briand::BriandTorRelayFlag::NOEDCONSENSUS) { 153 | output.append(prepend); 154 | output.append("NoEdConsensus"); 155 | output.append(separator); 156 | } 157 | if (flagMask & Briand::BriandTorRelayFlag::RUNNING) { 158 | output.append(prepend); 159 | output.append("Running"); 160 | output.append(separator); 161 | } 162 | if (flagMask & Briand::BriandTorRelayFlag::STABLE) { 163 | output.append(prepend); 164 | output.append("Stable"); 165 | output.append(separator); 166 | } 167 | if (flagMask & Briand::BriandTorRelayFlag::STABLEDESC) { 168 | output.append(prepend); 169 | output.append("StableDesc"); 170 | output.append(separator); 171 | } 172 | if (flagMask & Briand::BriandTorRelayFlag::V2DIR) { 173 | output.append(prepend); 174 | output.append("V2Dir"); 175 | output.append(separator); 176 | } 177 | if (flagMask & Briand::BriandTorRelayFlag::VALID) { 178 | output.append(prepend); 179 | output.append("Valid"); 180 | output.append(separator); 181 | } 182 | if (flagMask & Briand::BriandTorRelayFlag::AUTHORITY) { 183 | output.append(prepend); 184 | output.append("Authority"); 185 | output.append(separator); 186 | } 187 | 188 | if (output.length() > 0) 189 | output.resize(output.length() - separator.length()); // remove last separator 190 | 191 | return output; 192 | } 193 | 194 | string BriandUtils::GetPublicIP() { 195 | short httpCode = 0; 196 | string randomAgent = string( Briand::BriandUtils::GetRandomHostName().get() ); 197 | 198 | // Using APIFY but also ifconfig.me could be used 199 | //auto ipString = Briand::BriandNet::HttpsGet("api.ipfy.org", 443, "/", httpCode, randomAgent); 200 | // APIFY seems not so reliable, back to ifconfig 201 | auto ipString = Briand::BriandNet::HttpsGet("ifconfig.me", 443, "/ip", httpCode, randomAgent, true); 202 | 203 | if (ipString == nullptr) return "Error (HTTP/" + to_string(httpCode) + ")"; 204 | else return *ipString.get(); 205 | } 206 | 207 | void BriandUtils::PrintByteBuffer(const vector& buffer, const short& newLineAfterBytes /* = 0 */, const unsigned int& bytesToPrint /* = 0 */) { 208 | unsigned int limit; 209 | 210 | if (bytesToPrint > 0 && bytesToPrint < buffer.size()) limit = bytesToPrint; 211 | else limit = buffer.size(); 212 | 213 | for (unsigned int i=0; i < limit; i++) { 214 | printf("%02X", buffer.at(i)); 215 | if (newLineAfterBytes > 0 && i > 0 && i % newLineAfterBytes == 0) printf("\n"); 216 | } 217 | printf("\n"); 218 | } 219 | 220 | void BriandUtils::PrintOldStyleByteBuffer(unsigned char buffer[], const unsigned int& size, const short& newLineAfterBytes /* = 0 */, const unsigned int& bytesToPrint /* = 0 */) { 221 | unsigned int limit; 222 | 223 | if (buffer == NULL) { 224 | printf("(NULL)"); 225 | return; 226 | } 227 | 228 | if (bytesToPrint > 0 && bytesToPrint < size) limit = bytesToPrint; 229 | else limit = size; 230 | 231 | for (unsigned int i=0; i < limit; i++) { 232 | printf("%02X", buffer[i]); 233 | if (newLineAfterBytes > 0 && i > 0 && i % newLineAfterBytes == 0) printf("\n"); 234 | } 235 | printf("\n"); 236 | } 237 | 238 | string BriandUtils::BriandTorCellCommandToString(const Briand::BriandTorCellCommand& command) { 239 | if (command == Briand::BriandTorCellCommand::PADDING) return string("PADDING"); 240 | if (command == Briand::BriandTorCellCommand::CREATE) return string("CREATE"); 241 | if (command == Briand::BriandTorCellCommand::CREATED) return string("CREATED"); 242 | if (command == Briand::BriandTorCellCommand::RELAY) return string("RELAY"); 243 | if (command == Briand::BriandTorCellCommand::DESTROY) return string("DESTROY"); 244 | if (command == Briand::BriandTorCellCommand::CREATE_FAST) return string("CREATE_FAST"); 245 | if (command == Briand::BriandTorCellCommand::CREATED_FAST) return string("CREATED_FAST"); 246 | if (command == Briand::BriandTorCellCommand::NETINFO) return string("NETINFO"); 247 | if (command == Briand::BriandTorCellCommand::RELAY_EARLY) return string("RELAY_EARLY"); 248 | if (command == Briand::BriandTorCellCommand::CREATE2) return string("CREATE2"); 249 | if (command == Briand::BriandTorCellCommand::CREATED2) return string("CREATED2"); 250 | if (command == Briand::BriandTorCellCommand::PADDING_NEGOTIATE) return string("PADDING_NEGOTIATE"); 251 | if (command == Briand::BriandTorCellCommand::VERSIONS) return string("VERSIONS"); 252 | if (command == Briand::BriandTorCellCommand::VPADDING) return string("VPADDING"); 253 | if (command == Briand::BriandTorCellCommand::CERTS) return string("CERTS"); 254 | if (command == Briand::BriandTorCellCommand::AUTH_CHALLENGE) return string("AUTH_CHALLENGE"); 255 | if (command == Briand::BriandTorCellCommand::AUTHENTICATE) return string("AUTHENTICATE"); 256 | if (command == Briand::BriandTorCellCommand::AUTHORIZE) return string("AUTHORIZE"); 257 | 258 | return string("UNKNOWN"); 259 | } 260 | 261 | string BriandUtils::BriandTorRelayCellCommandToString(const Briand::BriandTorCellRelayCommand& command) { 262 | if (command == Briand::BriandTorCellRelayCommand::RELAY_BEGIN) return string("RELAY_BEGIN"); 263 | if (command == Briand::BriandTorCellRelayCommand::RELAY_BEGIN_DIR) return string("RELAY_BEGIN_DIR"); 264 | if (command == Briand::BriandTorCellRelayCommand::RELAY_CONNECTED) return string("RELAY_CONNECTED"); 265 | if (command == Briand::BriandTorCellRelayCommand::RELAY_DATA) return string("RELAY_DATA"); 266 | if (command == Briand::BriandTorCellRelayCommand::RELAY_DROP) return string("RELAY_DROP"); 267 | if (command == Briand::BriandTorCellRelayCommand::RELAY_END) return string("RELAY_END"); 268 | if (command == Briand::BriandTorCellRelayCommand::RELAY_EXTEND2) return string("RELAY_EXTEND2"); 269 | if (command == Briand::BriandTorCellRelayCommand::RELAY_EXTEND) return string("RELAY_EXTEND"); 270 | if (command == Briand::BriandTorCellRelayCommand::RELAY_EXTENDED2) return string("RELAY_EXTENDED2"); 271 | if (command == Briand::BriandTorCellRelayCommand::RELAY_EXTENDED) return string("RELAY_EXTENDED"); 272 | if (command == Briand::BriandTorCellRelayCommand::RELAY_RESOLVE) return string("RELAY_RESOLVE"); 273 | if (command == Briand::BriandTorCellRelayCommand::RELAY_RESOLVED) return string("RELAY_RESOLVED"); 274 | if (command == Briand::BriandTorCellRelayCommand::RELAY_SENDME) return string("RELAY_SENDME"); 275 | if (command == Briand::BriandTorCellRelayCommand::RELAY_TRUNCATE) return string("RELAY_TRUNCATE"); 276 | if (command == Briand::BriandTorCellRelayCommand::RELAY_TRUNCATED) return string("RELAY_TRUNCATED"); 277 | 278 | return string("UNKNOWN"); 279 | } 280 | 281 | unique_ptr BriandUtils::GetOneOldBuffer(const unsigned int& size) { 282 | auto buf = make_unique(size); 283 | // init to zero 284 | for (unsigned int i = 0; i> BriandUtils::ArrayToVector(const unique_ptr& input, const unsigned long int& size) { 298 | auto v = make_unique>(); 299 | v->reserve(size); 300 | 301 | if (input == nullptr) return std::move(v); 302 | 303 | for (int i = 0; i < size; i++) 304 | v->push_back(input[i]); 305 | return std::move(v); 306 | } 307 | 308 | unique_ptr BriandUtils::StringToOldBuffer(const string& input, bool nullterminate /* = false*/) { 309 | unsigned long int size = input.length(); 310 | 311 | if (nullterminate) size++; 312 | 313 | auto b = make_unique(size); 314 | for (unsigned long int i = 0; i < input.length(); i++) 315 | b[i] = input.at(i); 316 | 317 | return std::move(b); 318 | } 319 | 320 | string BriandUtils::OldBufferToString(unique_ptr& input, const unsigned long int& size) { 321 | string output(""); 322 | unsigned long int limit = size; 323 | 324 | if (input == nullptr) return output; 325 | 326 | // If null-terminated string, do not include 327 | if (input[size-1] == 0x00) limit--; 328 | 329 | for (unsigned long int i = 0; i < limit; i++) 330 | output.push_back(input[i]); 331 | 332 | return output; 333 | } 334 | 335 | unique_ptr> BriandUtils::HexStringToVector(const string& hexstring, const string& preNonHex) { 336 | auto v = make_unique>(); 337 | //v->reserve(hexstring.size() + preNonHex.size()); // reserve some bytes 338 | 339 | if (hexstring.length() % 2 != 0) 340 | return std::move(v); 341 | 342 | // Copy prepended if any 343 | for (unsigned long int i = 0; i < preNonHex.length(); i++) { 344 | v->push_back( static_cast( preNonHex.at(i) ) ); 345 | } 346 | 347 | // Copy other bytes, 2 digits per time 348 | for (unsigned long int i = 0; i < hexstring.length(); i+= 2) { 349 | string h(""); 350 | h.push_back(hexstring.at(i)); 351 | h.push_back(hexstring.at(i+1)); 352 | 353 | v->push_back( static_cast( std::stoi(h, 0, 16) ) ); 354 | } 355 | 356 | return std::move(v); 357 | } 358 | 359 | unique_ptr BriandUtils::HexStringToOldBuffer(const string& hexstring, unsigned int& size, const string& preNonhex, bool nullterm /* = false */) { 360 | unsigned int i = 0; 361 | unsigned int j = 0; 362 | 363 | size = (hexstring.length()/2) + preNonhex.length(); 364 | if( nullterm ) size++; 365 | 366 | auto buffer = make_unique(size); 367 | 368 | if (hexstring.length() % 2 != 0) 369 | return std::move(buffer); 370 | 371 | // init to zero is granted by make_unique 372 | 373 | // copy prepended if any 374 | for (i = 0; i < preNonhex.length(); i++) { 375 | buffer[j] = preNonhex.at(i); 376 | j++; 377 | } 378 | 379 | // Copy 2 digits per time 380 | for (i = 0; i < hexstring.length(); i += 2) { 381 | string b = string(""); 382 | b.push_back(hexstring.at(i)); 383 | b.push_back(hexstring.at(i+1)); 384 | 385 | buffer[j] = static_cast( stoi( b, 0, 16 ) ); 386 | j++; 387 | } 388 | 389 | return std::move(buffer); 390 | } 391 | 392 | void BriandUtils::PrintFileContent(const string& filename) { 393 | ifstream f; 394 | f.open(filename, ios::binary | ios::in); 395 | unsigned char c = f.get(); 396 | while (f.good()) { 397 | cout << c; 398 | c = f.get(); 399 | } 400 | f.close(); 401 | } 402 | 403 | void BriandUtils::StringTrimAll(string& input, char c) { 404 | input.erase(std::remove(input.begin(), input.end(), c),input.end()); 405 | } 406 | 407 | string BriandUtils::IPv4ToString(const in_addr& ip) { 408 | return string(inet_ntoa(ip)); 409 | } 410 | 411 | in_addr BriandUtils::IPv4FromString(const string& ip) { 412 | in_addr temp; 413 | bzero(&temp, sizeof(temp)); 414 | inet_aton(ip.c_str(), &temp); 415 | 416 | return temp; 417 | } 418 | 419 | string BriandUtils::RelayEndReasonToString(const BriandTorRelayEndReason& reason) { 420 | string s("(RESERVED)"); 421 | 422 | if (reason == BriandTorRelayEndReason::REASON_MISC) s = "REASON_MISC"; 423 | if (reason == BriandTorRelayEndReason::REASON_RESOLVEFAILED) s = "REASON_RESOLVEFAILED"; 424 | if (reason == BriandTorRelayEndReason::REASON_CONNECTREFUSED) s = "REASON_CONNECTREFUSED"; 425 | if (reason == BriandTorRelayEndReason::REASON_EXITPOLICY) s = "REASON_EXITPOLICY"; 426 | if (reason == BriandTorRelayEndReason::REASON_DESTROY) s = "REASON_DESTROY"; 427 | if (reason == BriandTorRelayEndReason::REASON_DONE) s = "REASON_DONE"; 428 | if (reason == BriandTorRelayEndReason::REASON_TIMEOUT) s = "REASON_TIMEOUT"; 429 | if (reason == BriandTorRelayEndReason::REASON_NOROUTE) s = "REASON_NOROUTE"; 430 | if (reason == BriandTorRelayEndReason::REASON_HIBERNATING) s = "REASON_HIBERNATING"; 431 | if (reason == BriandTorRelayEndReason::REASON_INTERNAL) s = "REASON_INTERNAL"; 432 | if (reason == BriandTorRelayEndReason::REASON_RESOURCELIMIT) s = "REASON_RESOURCELIMIT"; 433 | if (reason == BriandTorRelayEndReason::REASON_CONNRESET) s = "REASON_CONNRESET"; 434 | if (reason == BriandTorRelayEndReason::REASON_TORPROTOCOL) s = "REASON_TORPROTOCOL"; 435 | if (reason == BriandTorRelayEndReason::REASON_NOTDIRECTORY) s = "REASON_NOTDIRECTORY"; 436 | 437 | return s; 438 | } 439 | 440 | string BriandUtils::RelayTruncatedReasonToString(const BriandTorDestroyReason& reason) { 441 | string s("(RESERVED)"); 442 | 443 | if (reason == BriandTorDestroyReason::CHANNEL_CLOSED) s = "CHANNEL_CLOSED"; 444 | if (reason == BriandTorDestroyReason::CONNECTFAILED) s = "CONNECTFAILED"; 445 | if (reason == BriandTorDestroyReason::DESTROYED) s = "DESTROYED"; 446 | if (reason == BriandTorDestroyReason::FINISHED) s = "FINISHED"; 447 | if (reason == BriandTorDestroyReason::HIBERNATING) s = "HIBERNATING"; 448 | if (reason == BriandTorDestroyReason::INTERNAL) s = "INTERNAL"; 449 | if (reason == BriandTorDestroyReason::NONE) s = "NONE"; 450 | if (reason == BriandTorDestroyReason::NOSUCHSERVICE) s = "NOSUCHSERVICE"; 451 | if (reason == BriandTorDestroyReason::OR_IDENTITY) s = "OR_IDENTITY"; 452 | if (reason == BriandTorDestroyReason::PROTOCOL) s = "PROTOCOL"; 453 | if (reason == BriandTorDestroyReason::REQUESTED) s = "REQUESTED"; 454 | if (reason == BriandTorDestroyReason::RESOURCELIMIT) s = "RESOURCELIMIT"; 455 | if (reason == BriandTorDestroyReason::TIMEOUT) s = "TIMEOUT"; 456 | 457 | return s; 458 | } 459 | 460 | bool BriandUtils::IsNumber(const string& doubt) { 461 | for (const char& c : doubt) { 462 | if (c < 48 || c > 57) 463 | return false; 464 | } 465 | 466 | return true; 467 | } 468 | 469 | const char* BriandUtils::BriandErrorStr(const BriandError& errorCode) { 470 | switch (errorCode) 471 | { 472 | case BriandError::BRIAND_ERR_OK : return "OK"; 473 | case BriandError::BRIAND_ERR_NONE : return "NONE"; 474 | case BriandError::BRIAND_ERR_DIGEST_NOT_MATCHING : return "DIGEST_NOT_MATCHING"; 475 | case BriandError::BRIAND_ERR_INSUFFICIENT_PAYLOAD_BYTES : return "INSUFFICIENT_PAYLOAD_BYTES"; 476 | case BriandError::BRIAND_ERR_NOT_RELAY_CELL : return "NOT_RELAY_CELL"; 477 | case BriandError::BRIAND_ERR_RECOGNIZED_NOT_ZERO : return "RECOGNIZED_NOT_ZERO"; 478 | case BriandError::BRIAND_ERR_STREAMID_NOT_MATCHING_NOR_ZERO : return "STREAMID_NOT_MATCHING_NOR_ZERO"; 479 | 480 | default: return std::to_string(errorCode).c_str(); 481 | } 482 | } 483 | 484 | } 485 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file was automatically generated for projects 2 | # without default 'CMakeLists.txt' file. 3 | 4 | FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) 5 | 6 | idf_component_register(SRCS ${app_sources}) 7 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | --------------------------------------------------------------------------------