gnunet-daemon-testbed-underlay.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2008--2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file testbed/gnunet-daemon-testbed-blacklist.c
  18. * @brief daemon to restrict incoming connections from other peers at the
  19. * transport layer of a peer
  20. * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_transport_service.h"
  25. #include "gnunet_transport_manipulation_service.h"
  26. #include "gnunet_ats_service.h"
  27. #include "gnunet_testing_lib.h"
  28. #include <sqlite3.h>
  29. /**
  30. * Logging shorthand
  31. */
  32. #define LOG(type, ...) \
  33. GNUNET_log (type, __VA_ARGS__)
  34. /**
  35. * Debug logging shorthand
  36. */
  37. #define DEBUG(...) \
  38. LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
  39. /**
  40. * Log an error message at log-level 'level' that indicates
  41. * a failure of the command 'cmd' on file 'filename'
  42. * with the message given by strerror(errno).
  43. */
  44. #define LOG_SQLITE(db, msg, level, cmd) \
  45. do { \
  46. GNUNET_log_from (level, "sqlite", _ ( \
  47. "`%s' failed at %s:%d with error: %s\n"), \
  48. cmd, __FILE__, __LINE__, sqlite3_errmsg (db)); \
  49. if (msg != NULL) \
  50. GNUNET_asprintf (msg, _ ("`%s' failed at %s:%u with error: %s"), cmd, \
  51. __FILE__, __LINE__, sqlite3_errmsg (db)); \
  52. } while (0)
  53. /**
  54. * The map to store the peer identities to allow/deny
  55. */
  56. static struct GNUNET_CONTAINER_MultiPeerMap *map;
  57. /**
  58. * The database connection
  59. */
  60. static struct sqlite3 *db;
  61. /**
  62. * The blacklist handle we obtain from transport when we register ourselves for
  63. * access control
  64. */
  65. static struct GNUNET_TRANSPORT_Blacklist *bh;
  66. /**
  67. * The hostkeys file
  68. */
  69. struct GNUNET_DISK_FileHandle *hostkeys_fd;
  70. /**
  71. * The hostkeys map
  72. */
  73. static struct GNUNET_DISK_MapHandle *hostkeys_map;
  74. /**
  75. * The hostkeys data
  76. */
  77. static void *hostkeys_data;
  78. /**
  79. * Handle to the transport service. This is used for setting link metrics
  80. */
  81. static struct GNUNET_TRANSPORT_ManipulationHandle *transport;
  82. /**
  83. * The number of hostkeys in the hostkeys array
  84. */
  85. static unsigned int num_hostkeys;
  86. /**
  87. * @ingroup hashmap
  88. * Iterator over hash map entries.
  89. *
  90. * @param cls closure
  91. * @param key current key code
  92. * @param value value in the hash map
  93. * @return #GNUNET_YES if we should continue to
  94. * iterate,
  95. * #GNUNET_NO if not.
  96. */
  97. static int
  98. iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
  99. {
  100. GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
  101. value));
  102. return GNUNET_YES;
  103. }
  104. /**
  105. * Cleaup and destroy the map
  106. */
  107. static void
  108. cleanup_map ()
  109. {
  110. if (NULL != map)
  111. {
  112. GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_iterate (map,
  113. &
  114. iterator,
  115. NULL));
  116. GNUNET_CONTAINER_multipeermap_destroy (map);
  117. map = NULL;
  118. }
  119. }
  120. /**
  121. * Function that decides if a connection is acceptable or not.
  122. *
  123. * @param cls closure
  124. * @param pid peer to approve or disapproave
  125. * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
  126. */
  127. static int
  128. check_access (void *cls, const struct GNUNET_PeerIdentity *pid)
  129. {
  130. int contains;
  131. GNUNET_assert (NULL != map);
  132. contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
  133. if (GNUNET_YES == contains)
  134. {
  135. DEBUG ("Permitting `%s'\n", GNUNET_i2s (pid));
  136. return GNUNET_OK;
  137. }
  138. DEBUG ("Not permitting `%s'\n", GNUNET_i2s (pid));
  139. return GNUNET_SYSERR;
  140. }
  141. static int
  142. get_identity (unsigned int offset,
  143. struct GNUNET_PeerIdentity *id)
  144. {
  145. struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
  146. if (offset >= num_hostkeys)
  147. return GNUNET_SYSERR;
  148. GNUNET_memcpy (&private_key,
  149. hostkeys_data + (offset * GNUNET_TESTING_HOSTKEYFILESIZE),
  150. GNUNET_TESTING_HOSTKEYFILESIZE);
  151. GNUNET_CRYPTO_eddsa_key_get_public (&private_key,
  152. &id->public_key);
  153. return GNUNET_OK;
  154. }
  155. /**
  156. * Whilelist entry
  157. */
  158. struct WhiteListRow
  159. {
  160. /**
  161. * Next ptr
  162. */
  163. struct WhiteListRow *next;
  164. /**
  165. * The offset where to find the hostkey for the peer
  166. */
  167. unsigned int id;
  168. /**
  169. * Latency to be assigned to the link
  170. */
  171. int latency;
  172. };
  173. /**
  174. * Function to load keys
  175. */
  176. static int
  177. load_keys (const struct GNUNET_CONFIGURATION_Handle *c)
  178. {
  179. char *data_dir;
  180. char *idfile;
  181. uint64_t fsize;
  182. data_dir = NULL;
  183. idfile = NULL;
  184. fsize = 0;
  185. data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
  186. GNUNET_asprintf (&idfile, "%s/testing_hostkeys.ecc", data_dir);
  187. GNUNET_free (data_dir);
  188. data_dir = NULL;
  189. if (GNUNET_OK !=
  190. GNUNET_DISK_file_size (idfile, &fsize, GNUNET_YES, GNUNET_YES))
  191. {
  192. GNUNET_free (idfile);
  193. return GNUNET_SYSERR;
  194. }
  195. if (0 != (fsize % GNUNET_TESTING_HOSTKEYFILESIZE))
  196. {
  197. LOG (GNUNET_ERROR_TYPE_ERROR,
  198. _ ("Incorrect hostkey file format: %s\n"), idfile);
  199. GNUNET_free (idfile);
  200. return GNUNET_SYSERR;
  201. }
  202. hostkeys_fd = GNUNET_DISK_file_open (idfile, GNUNET_DISK_OPEN_READ,
  203. GNUNET_DISK_PERM_NONE);
  204. if (NULL == hostkeys_fd)
  205. {
  206. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", idfile);
  207. GNUNET_free (idfile);
  208. return GNUNET_SYSERR;
  209. }
  210. GNUNET_free (idfile);
  211. idfile = NULL;
  212. hostkeys_data = GNUNET_DISK_file_map (hostkeys_fd,
  213. &hostkeys_map,
  214. GNUNET_DISK_MAP_TYPE_READ,
  215. fsize);
  216. if (NULL == hostkeys_data)
  217. {
  218. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "mmap");
  219. return GNUNET_SYSERR;
  220. }
  221. num_hostkeys = fsize / GNUNET_TESTING_HOSTKEYFILESIZE;
  222. return GNUNET_OK;
  223. }
  224. /**
  225. * Function to unload keys
  226. */
  227. static void
  228. unload_keys ()
  229. {
  230. if (NULL != hostkeys_map)
  231. {
  232. GNUNET_assert (NULL != hostkeys_data);
  233. GNUNET_DISK_file_unmap (hostkeys_map);
  234. hostkeys_map = NULL;
  235. hostkeys_data = NULL;
  236. }
  237. if (NULL != hostkeys_fd)
  238. {
  239. GNUNET_DISK_file_close (hostkeys_fd);
  240. hostkeys_fd = NULL;
  241. }
  242. }
  243. /**
  244. * Shutdown task to cleanup our resources and exit.
  245. *
  246. * @param cls NULL
  247. */
  248. static void
  249. do_shutdown (void *cls)
  250. {
  251. if (NULL != transport)
  252. {
  253. GNUNET_TRANSPORT_manipulation_disconnect (transport);
  254. transport = NULL;
  255. }
  256. cleanup_map ();
  257. unload_keys ();
  258. if (NULL != bh)
  259. GNUNET_TRANSPORT_blacklist_cancel (bh);
  260. }
  261. /**
  262. * Function to read whitelist rows from the database
  263. *
  264. * @param db the database connection
  265. * @param pid the identity of this peer
  266. * @param wl_rows where to store the retrieved whitelist rows
  267. * @return GNUNET_SYSERR upon error OR the number of rows retrieved
  268. */
  269. static int
  270. db_read_whitelist (struct sqlite3 *db, int pid, struct WhiteListRow **wl_rows)
  271. {
  272. static const char *query_wl =
  273. "SELECT oid, latency FROM whitelist WHERE (id == ?);";
  274. struct sqlite3_stmt *stmt_wl;
  275. struct WhiteListRow *lr;
  276. int nrows;
  277. int ret;
  278. if (SQLITE_OK != (ret = sqlite3_prepare_v2 (db, query_wl, -1, &stmt_wl,
  279. NULL)))
  280. {
  281. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
  282. return GNUNET_SYSERR;
  283. }
  284. if (SQLITE_OK != (ret = sqlite3_bind_int (stmt_wl, 1, pid)))
  285. {
  286. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
  287. sqlite3_finalize (stmt_wl);
  288. return GNUNET_SYSERR;
  289. }
  290. nrows = 0;
  291. do
  292. {
  293. ret = sqlite3_step (stmt_wl);
  294. if (SQLITE_ROW != ret)
  295. break;
  296. nrows++;
  297. lr = GNUNET_new (struct WhiteListRow);
  298. lr->id = sqlite3_column_int (stmt_wl, 0);
  299. lr->latency = sqlite3_column_int (stmt_wl, 1);
  300. lr->next = *wl_rows;
  301. *wl_rows = lr;
  302. }
  303. while (1);
  304. sqlite3_finalize (stmt_wl);
  305. return nrows;
  306. }
  307. /**
  308. * Main function that will be run.
  309. *
  310. * @param cls closure
  311. * @param args remaining command-line arguments
  312. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  313. * @param c configuration
  314. */
  315. static void
  316. run (void *cls, char *const *args, const char *cfgfile,
  317. const struct GNUNET_CONFIGURATION_Handle *c)
  318. {
  319. char *dbfile;
  320. struct WhiteListRow *wl_head;
  321. struct WhiteListRow *wl_entry;
  322. struct GNUNET_PeerIdentity identity;
  323. struct GNUNET_ATS_Properties prop;
  324. struct GNUNET_TIME_Relative delay;
  325. unsigned long long pid;
  326. unsigned int nrows;
  327. int ret;
  328. if (GNUNET_OK !=
  329. GNUNET_CONFIGURATION_get_value_number (c, "TESTBED",
  330. "PEERID", &pid))
  331. {
  332. GNUNET_break (0);
  333. return;
  334. }
  335. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
  336. "TESTBED-UNDERLAY",
  337. "DBFILE",
  338. &dbfile))
  339. {
  340. GNUNET_break (0);
  341. return;
  342. }
  343. if (SQLITE_OK != (ret = sqlite3_open_v2 (dbfile, &db, SQLITE_OPEN_READONLY,
  344. NULL)))
  345. {
  346. if (NULL != db)
  347. {
  348. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
  349. GNUNET_break (SQLITE_OK == sqlite3_close (db));
  350. }
  351. else
  352. LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
  353. GNUNET_free (dbfile);
  354. return;
  355. }
  356. DEBUG ("Opened database %s\n", dbfile);
  357. GNUNET_free (dbfile);
  358. dbfile = NULL;
  359. wl_head = NULL;
  360. if (GNUNET_OK != load_keys (c))
  361. goto close_db;
  362. transport = GNUNET_TRANSPORT_manipulation_connect (c);
  363. if (NULL == transport)
  364. {
  365. GNUNET_break (0);
  366. return;
  367. }
  368. /* read and process whitelist */
  369. nrows = 0;
  370. wl_head = NULL;
  371. nrows = db_read_whitelist (db, pid, &wl_head);
  372. if ((GNUNET_SYSERR == nrows) || (0 == nrows))
  373. {
  374. GNUNET_TRANSPORT_manipulation_disconnect (transport);
  375. goto close_db;
  376. }
  377. map = GNUNET_CONTAINER_multipeermap_create (nrows, GNUNET_NO);
  378. while (NULL != (wl_entry = wl_head))
  379. {
  380. wl_head = wl_entry->next;
  381. delay.rel_value_us = wl_entry->latency;
  382. memset (&prop, 0, sizeof(prop));
  383. GNUNET_assert (GNUNET_OK == get_identity (wl_entry->id, &identity));
  384. GNUNET_break (GNUNET_OK ==
  385. GNUNET_CONTAINER_multipeermap_put (map, &identity, &identity,
  386. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
  387. DEBUG ("Setting %u ms latency to peer `%s'\n",
  388. wl_entry->latency,
  389. GNUNET_i2s (&identity));
  390. GNUNET_TRANSPORT_manipulation_set (transport,
  391. &identity,
  392. &prop,
  393. delay,
  394. delay);
  395. GNUNET_free (wl_entry);
  396. }
  397. bh = GNUNET_TRANSPORT_blacklist (c, &check_access, NULL);
  398. GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
  399. close_db:
  400. GNUNET_break (SQLITE_OK == sqlite3_close (db));
  401. }
  402. /**
  403. * The main function.
  404. *
  405. * @param argc number of arguments from the command line
  406. * @param argv command line arguments
  407. * @return 0 ok, 1 on error
  408. */
  409. int
  410. main (int argc, char *const *argv)
  411. {
  412. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  413. GNUNET_GETOPT_OPTION_END
  414. };
  415. int ret;
  416. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  417. return 2;
  418. #ifdef SQLITE_CONFIG_MMAP_SIZE
  419. (void) sqlite3_config (SQLITE_CONFIG_MMAP_SIZE, 512000, 256000000);
  420. #endif
  421. ret =
  422. (GNUNET_OK ==
  423. GNUNET_PROGRAM_run (argc, argv, "testbed-underlay",
  424. _
  425. (
  426. "Daemon to restrict underlay network in testbed deployments"),
  427. options, &run, NULL)) ? 0 : 1;
  428. GNUNET_free ((void *) argv);
  429. return ret;
  430. }