gnunet-daemon-testbed-underlay.c 12 KB

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