CovertProtocol.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #ifndef COVERTPROTOCOL_H
  2. #define COVERTPROTOCOL_H
  3. #include <fstream>
  4. #include <iostream>
  5. #include <string>
  6. #include <type_traits>
  7. #include <boost/filesystem.hpp>
  8. #include "../../Config.h"
  9. #include "../../Notifications.h"
  10. #include "../../Queue.h"
  11. #include "../ChannelControls.h"
  12. /**
  13. * @class CovertProtocol
  14. *
  15. * An unidirectional Covert Channel protocol with a variable size template.
  16. *
  17. * The protocol works unidirectional so the active side uses send to encode data to be sent and the passive side uses receive to extract data.
  18. *
  19. * @param N number of bytes which can be used to transmit data
  20. * @param PASSIVE passive mode
  21. */
  22. template <int N, bool PASSIVE> class CovertProtocol : public ChannelControls {
  23. static_assert(N >= 1);
  24. public:
  25. /**
  26. * CovertProtocol constructor
  27. */
  28. CovertProtocol() : fileDirectory(Config::getValue("filedirectory")) {}
  29. /**
  30. * CovertProtocol destructor
  31. *
  32. * Closes the file
  33. */
  34. ~CovertProtocol() { file.close(); }
  35. /**
  36. * send encodes the data into the data array
  37. *
  38. * 1. Send file name size (length)
  39. * 2. Send file name
  40. * 3. Send data size (length)
  41. * 4. Send data
  42. *
  43. * @param data must be an array of size N
  44. */
  45. void send(uint8_t *const data) {
  46. static_assert(!PASSIVE);
  47. switch (state) {
  48. case ProtocolState::idle:
  49. data[0] = 0;
  50. return;
  51. case ProtocolState::fileNameSize:
  52. fileNameSize = fileName.size();
  53. data[0] = fileNameSize;
  54. fileNamePosition = 0;
  55. state = ProtocolState::fileName;
  56. break;
  57. case ProtocolState::fileName:
  58. if (fileNameSize - fileNamePosition >= N) {
  59. for (int i = 0; i < N; i++) {
  60. data[i] = fileName.at(fileNamePosition++);
  61. }
  62. } else {
  63. int diff = fileNameSize - fileNamePosition;
  64. for (int i = 0; i < diff; i++) {
  65. data[i] = fileName.at(fileNamePosition++);
  66. }
  67. }
  68. if (fileNamePosition == fileNameSize) {
  69. file.open(fileDirectory + fileName, std::ios::in | std::ios::binary | std::ios::ate);
  70. if (!file.is_open()) {
  71. file.close();
  72. std::cerr << "File \"" << fileName << "\" does exists. Resetting!!!" << std::endl;
  73. Notifications::newNotification("File \"" + fileName + "\" does not exists. Skipping.");
  74. // state = ProtocolState::error;
  75. Queue::channel->reset();
  76. return;
  77. }
  78. dataSize = file.tellg();
  79. dataPosition = 0;
  80. file.seekg(std::ios::beg);
  81. state = ProtocolState::dataSize;
  82. }
  83. break;
  84. case ProtocolState::dataSize:
  85. if constexpr (N >= 4) {
  86. for (; dataPosition < 4; dataPosition++) {
  87. data[dataPosition] = dataSize >> ((3 - dataPosition) * 8);
  88. }
  89. } else {
  90. uint32_t oldDataPosition = dataPosition;
  91. uint32_t limit = dataPosition + N;
  92. if (limit > 4) {
  93. limit = 4;
  94. }
  95. for (; dataPosition < limit; dataPosition++) {
  96. data[dataPosition - oldDataPosition] = dataSize >> ((3 - dataPosition) * 8);
  97. }
  98. }
  99. if (dataPosition == 4) {
  100. dataPosition = 0;
  101. state = ProtocolState::data;
  102. }
  103. break;
  104. case ProtocolState::data:
  105. if (dataSize - dataPosition >= N) {
  106. file.read((char *)data, N);
  107. dataPosition += N;
  108. } else {
  109. file.read((char *)data, dataSize - dataPosition);
  110. dataPosition = dataSize;
  111. }
  112. std::cout << "sent " << dataPosition << "/" << dataSize << std::endl;
  113. if (dataPosition == dataSize) {
  114. file.close();
  115. state = ProtocolState::idle;
  116. std::cout << "finished sending file \"" << fileName << "\"" << std::endl;
  117. Notifications::newNotification("Finished sending file \"" + fileName + "\".");
  118. // schedule next file transfer
  119. Queue::schedule();
  120. }
  121. break;
  122. case ProtocolState::error:
  123. Queue::channel->reset();
  124. break;
  125. }
  126. return;
  127. }
  128. /**
  129. * receive extracts data from the data array
  130. *
  131. * 1. Receive file name size (length)
  132. * 2. Receive file name
  133. * 3. Receive data size (length)
  134. * 4. Receive data
  135. *
  136. * @param data must be an array of size N
  137. */
  138. void receive(const uint8_t *const data) {
  139. static_assert(PASSIVE);
  140. switch (state) {
  141. case ProtocolState::idle:
  142. if (data[0] == 0) {
  143. return;
  144. }
  145. // no break because the first data received is the filename size
  146. case ProtocolState::fileNameSize:
  147. Notifications::newNotification("Incoming transmission.");
  148. std::cout << "incoming file transmission" << std::endl;
  149. fileNameSize = data[0];
  150. fileNamePosition = 0;
  151. fileName = "";
  152. transferStart = std::time(nullptr);
  153. state = ProtocolState::fileName;
  154. break;
  155. case ProtocolState::fileName:
  156. if (fileNameSize - fileNamePosition >= N) {
  157. uint8_t oldFileNamePosition = fileNamePosition;
  158. for (; fileNamePosition < oldFileNamePosition + N; fileNamePosition++) {
  159. fileName += data[fileNamePosition - oldFileNamePosition];
  160. }
  161. } else {
  162. uint8_t oldFileNamePosition = fileNamePosition;
  163. for (; fileNamePosition < fileNameSize; fileNamePosition++) {
  164. fileName += data[fileNamePosition - oldFileNamePosition];
  165. }
  166. }
  167. if (fileNamePosition == fileNameSize) {
  168. file.open(fileDirectory + fileName, std::ios::in);
  169. if (file.is_open()) {
  170. file.close();
  171. std::cerr << "File \"" << fileName << "\" already exists. Resetting!!!" << std::endl;
  172. Notifications::newNotification("File \"" + fileName + "\" already exists. Skipping.");
  173. // state = ProtocolState::error;
  174. Queue::channel->reset();
  175. return;
  176. }
  177. file.close();
  178. file.open(fileDirectory + fileName, std::ios::out | std::ios::binary | std::ios::app);
  179. if (!file.is_open()) {
  180. std::cerr << "File \"" << fileName << "\" could not be opened! Resetting!!!" << std::endl;
  181. Notifications::newNotification("File \"" + fileName + "\" could not be written. Skipping.");
  182. // state = ProtocolState::error;
  183. Queue::channel->reset();
  184. return;
  185. }
  186. dataSize = 0;
  187. dataPosition = 0;
  188. state = ProtocolState::dataSize;
  189. std::cout << "starting receiving file \"" << fileName << "\"" << std::endl;
  190. Notifications::newNotification("Receiving file \"" + fileName + "\".");
  191. }
  192. break;
  193. case ProtocolState::dataSize:
  194. if constexpr (N >= 4) {
  195. for (; dataPosition < 4; dataPosition++) {
  196. dataSize = dataSize | data[dataPosition] << ((3 - dataPosition) * 8);
  197. }
  198. } else {
  199. uint32_t oldDataPosition = dataPosition;
  200. uint32_t limit = dataPosition + N;
  201. if (limit > 4) {
  202. limit = 4;
  203. }
  204. for (; dataPosition < limit; dataPosition++) {
  205. dataSize = dataSize | data[dataPosition - oldDataPosition] << ((3 - dataPosition) * 8);
  206. }
  207. }
  208. if (dataPosition == 4) {
  209. dataPosition = 0;
  210. state = ProtocolState::data;
  211. }
  212. break;
  213. case ProtocolState::data:
  214. if (dataSize - dataPosition >= N) {
  215. file.write((char *)data, N);
  216. dataPosition += N;
  217. } else {
  218. file.write((char *)data, dataSize - dataPosition);
  219. dataPosition = dataSize;
  220. }
  221. std::cout << "received " << dataPosition << "/" << dataSize << std::endl;
  222. if (dataPosition == dataSize) {
  223. file.close();
  224. state = ProtocolState::idle;
  225. std::cout << "finished receiving file \"" << fileName << "\"" << std::endl;
  226. Notifications::newNotification("Finished receiving file \"" + fileName + "\".");
  227. }
  228. break;
  229. case ProtocolState::error:
  230. //
  231. break;
  232. }
  233. }
  234. /* ChannelControls */
  235. /**
  236. * Starts sending a file.
  237. *
  238. * Starts sending a file if no transmission is running and the file exists.
  239. *
  240. * @param fileName name of the file in the file directory
  241. * @return true - file will be sent | false - file was not accepted
  242. */
  243. virtual bool sendFile(const std::string &fileName) {
  244. if constexpr (PASSIVE) {
  245. return false;
  246. }
  247. if (state != ProtocolState::idle || file.is_open()) {
  248. return false;
  249. }
  250. file.open(fileDirectory + fileName, std::ios::in);
  251. if (file.is_open()) {
  252. file.close();
  253. this->fileName = fileName;
  254. transferStart = std::time(nullptr);
  255. state = ProtocolState::fileNameSize;
  256. Notifications::newNotification("Start sending file \"" + fileName + "\".");
  257. std::cout << "starting sending file \"" << fileName << "\"" << std::endl;
  258. return true;
  259. } else {
  260. return false;
  261. }
  262. }
  263. /**
  264. * Get the progress
  265. *
  266. * @return progress counters
  267. */
  268. virtual std::pair<uint32_t, uint32_t> getProgress() {
  269. if (state == ProtocolState::data) {
  270. return std::pair<uint32_t, uint32_t>(dataPosition, dataSize);
  271. } else {
  272. return std::pair<uint32_t, uint32_t>(0, 0);
  273. }
  274. }
  275. /**
  276. * Test if a transfer is running
  277. *
  278. * @return true - a transfer runs | false - no transfer runs
  279. */
  280. virtual bool isTransferRunning() { return state != ProtocolState::idle; }
  281. /**
  282. * Resets protocol state
  283. */
  284. virtual void reset() {
  285. file.close();
  286. if (PASSIVE && state == ProtocolState::data) {
  287. // delete file if in passive mode and data has been received
  288. deleteFile(fileName);
  289. Notifications::newNotification("Transfer of file \"" + fileName + "\" was aborted.");
  290. }
  291. state = ProtocolState::idle;
  292. dataSize = 0;
  293. dataPosition = 0;
  294. fileNameSize = 0;
  295. fileNamePosition = 0;
  296. fileName = "";
  297. Queue::schedule();
  298. }
  299. /**
  300. * Test if a transfer is running
  301. *
  302. * @return true - a transfer runs | false - no transfer runs
  303. */
  304. virtual std::time_t getTransferStart() { return transferStart; }
  305. /**
  306. * Get file name of the file which is currently be sent or received.
  307. *
  308. * @return file name
  309. */
  310. virtual std::string getFileName() { return fileName; };
  311. /* =============== */
  312. private:
  313. /**
  314. * folder of the files
  315. */
  316. const std::string fileDirectory;
  317. /**
  318. * States of the data transmission
  319. *
  320. * @warning error state cannot be recovered!!!
  321. */
  322. enum struct ProtocolState { idle, fileNameSize, fileName, dataSize, data, error };
  323. /**
  324. * State of the data transmission
  325. */
  326. ProtocolState state = ProtocolState::idle;
  327. /**
  328. * size of the file to be sent/received
  329. */
  330. uint32_t dataSize;
  331. /**
  332. * position in the file to be sent/received
  333. */
  334. uint32_t dataPosition;
  335. /**
  336. * file to be sent/received
  337. */
  338. std::fstream file;
  339. /**
  340. * size of the file name
  341. */
  342. uint8_t fileNameSize;
  343. /**
  344. * position of the file name so far sent/received
  345. */
  346. uint8_t fileNamePosition;
  347. /**
  348. * Deletes a file
  349. */
  350. void deleteFile(const std::string &fileName) {
  351. std::string fname = this->fileDirectory;
  352. fname.append(fileName);
  353. if (boost::filesystem::exists(fname)) {
  354. boost::filesystem::remove(fname);
  355. }
  356. }
  357. };
  358. #endif