123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /*
- This file is part of GNUnet
- Copyright (C) 2008--2013 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file testbed/gnunet-daemon-testbed-blacklist.c
- * @brief daemon to restrict incoming connections from other peers at the
- * transport layer of a peer
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
- #include "platform.h"
- #include "gnunet_util_lib.h"
- #include "gnunet_transport_service.h"
- #include "gnunet_transport_manipulation_service.h"
- #include "gnunet_ats_service.h"
- #include "gnunet_testing_lib.h"
- #include <sqlite3.h>
- /**
- * Logging shorthand
- */
- #define LOG(type, ...) \
- GNUNET_log (type, __VA_ARGS__)
- /**
- * Debug logging shorthand
- */
- #define DEBUG(...) \
- LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
- /**
- * Log an error message at log-level 'level' that indicates
- * a failure of the command 'cmd' on file 'filename'
- * with the message given by strerror(errno).
- */
- #define LOG_SQLITE(db, msg, level, cmd) \
- do { \
- GNUNET_log_from (level, "sqlite", _ ( \
- "`%s' failed at %s:%d with error: %s\n"), \
- cmd, __FILE__, __LINE__, sqlite3_errmsg (db)); \
- if (msg != NULL) \
- GNUNET_asprintf (msg, _ ("`%s' failed at %s:%u with error: %s"), cmd, \
- __FILE__, __LINE__, sqlite3_errmsg (db)); \
- } while (0)
- /**
- * The map to store the peer identities to allow/deny
- */
- static struct GNUNET_CONTAINER_MultiPeerMap *map;
- /**
- * The database connection
- */
- static struct sqlite3 *db;
- /**
- * The blacklist handle we obtain from transport when we register ourselves for
- * access control
- */
- static struct GNUNET_TRANSPORT_Blacklist *bh;
- /**
- * The hostkeys file
- */
- struct GNUNET_DISK_FileHandle *hostkeys_fd;
- /**
- * The hostkeys map
- */
- static struct GNUNET_DISK_MapHandle *hostkeys_map;
- /**
- * The hostkeys data
- */
- static void *hostkeys_data;
- /**
- * Handle to the transport service. This is used for setting link metrics
- */
- static struct GNUNET_TRANSPORT_ManipulationHandle *transport;
- /**
- * The number of hostkeys in the hostkeys array
- */
- static unsigned int num_hostkeys;
- /**
- * @ingroup hashmap
- * Iterator over hash map entries.
- *
- * @param cls closure
- * @param key current key code
- * @param value value in the hash map
- * @return #GNUNET_YES if we should continue to
- * iterate,
- * #GNUNET_NO if not.
- */
- static int
- iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
- {
- GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
- value));
- return GNUNET_YES;
- }
- /**
- * Cleaup and destroy the map
- */
- static void
- cleanup_map ()
- {
- if (NULL != map)
- {
- GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_iterate (map,
- &
- iterator,
- NULL));
- GNUNET_CONTAINER_multipeermap_destroy (map);
- map = NULL;
- }
- }
- /**
- * Function that decides if a connection is acceptable or not.
- *
- * @param cls closure
- * @param pid peer to approve or disapproave
- * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
- */
- static int
- check_access (void *cls, const struct GNUNET_PeerIdentity *pid)
- {
- int contains;
- GNUNET_assert (NULL != map);
- contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
- if (GNUNET_YES == contains)
- {
- DEBUG ("Permitting `%s'\n", GNUNET_i2s (pid));
- return GNUNET_OK;
- }
- DEBUG ("Not permitting `%s'\n", GNUNET_i2s (pid));
- return GNUNET_SYSERR;
- }
- static int
- get_identity (unsigned int offset,
- struct GNUNET_PeerIdentity *id)
- {
- struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
- if (offset >= num_hostkeys)
- return GNUNET_SYSERR;
- GNUNET_memcpy (&private_key,
- hostkeys_data + (offset * GNUNET_TESTING_HOSTKEYFILESIZE),
- GNUNET_TESTING_HOSTKEYFILESIZE);
- GNUNET_CRYPTO_eddsa_key_get_public (&private_key,
- &id->public_key);
- return GNUNET_OK;
- }
- /**
- * Whilelist entry
- */
- struct WhiteListRow
- {
- /**
- * Next ptr
- */
- struct WhiteListRow *next;
- /**
- * The offset where to find the hostkey for the peer
- */
- unsigned int id;
- /**
- * Latency to be assigned to the link
- */
- int latency;
- };
- /**
- * Function to load keys
- */
- static int
- load_keys (const struct GNUNET_CONFIGURATION_Handle *c)
- {
- char *data_dir;
- char *idfile;
- uint64_t fsize;
- data_dir = NULL;
- idfile = NULL;
- fsize = 0;
- data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
- GNUNET_asprintf (&idfile, "%s/testing_hostkeys.ecc", data_dir);
- GNUNET_free (data_dir);
- data_dir = NULL;
- if (GNUNET_OK !=
- GNUNET_DISK_file_size (idfile, &fsize, GNUNET_YES, GNUNET_YES))
- {
- GNUNET_free (idfile);
- return GNUNET_SYSERR;
- }
- if (0 != (fsize % GNUNET_TESTING_HOSTKEYFILESIZE))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _ ("Incorrect hostkey file format: %s\n"), idfile);
- GNUNET_free (idfile);
- return GNUNET_SYSERR;
- }
- hostkeys_fd = GNUNET_DISK_file_open (idfile, GNUNET_DISK_OPEN_READ,
- GNUNET_DISK_PERM_NONE);
- if (NULL == hostkeys_fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", idfile);
- GNUNET_free (idfile);
- return GNUNET_SYSERR;
- }
- GNUNET_free (idfile);
- idfile = NULL;
- hostkeys_data = GNUNET_DISK_file_map (hostkeys_fd,
- &hostkeys_map,
- GNUNET_DISK_MAP_TYPE_READ,
- fsize);
- if (NULL == hostkeys_data)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "mmap");
- return GNUNET_SYSERR;
- }
- num_hostkeys = fsize / GNUNET_TESTING_HOSTKEYFILESIZE;
- return GNUNET_OK;
- }
- /**
- * Function to unload keys
- */
- static void
- unload_keys ()
- {
- if (NULL != hostkeys_map)
- {
- GNUNET_assert (NULL != hostkeys_data);
- GNUNET_DISK_file_unmap (hostkeys_map);
- hostkeys_map = NULL;
- hostkeys_data = NULL;
- }
- if (NULL != hostkeys_fd)
- {
- GNUNET_DISK_file_close (hostkeys_fd);
- hostkeys_fd = NULL;
- }
- }
- /**
- * Shutdown task to cleanup our resources and exit.
- *
- * @param cls NULL
- */
- static void
- do_shutdown (void *cls)
- {
- if (NULL != transport)
- {
- GNUNET_TRANSPORT_manipulation_disconnect (transport);
- transport = NULL;
- }
- cleanup_map ();
- unload_keys ();
- if (NULL != bh)
- GNUNET_TRANSPORT_blacklist_cancel (bh);
- }
- /**
- * Function to read whitelist rows from the database
- *
- * @param db the database connection
- * @param pid the identity of this peer
- * @param wl_rows where to store the retrieved whitelist rows
- * @return GNUNET_SYSERR upon error OR the number of rows retrieved
- */
- static int
- db_read_whitelist (struct sqlite3 *db, int pid, struct WhiteListRow **wl_rows)
- {
- static const char *query_wl =
- "SELECT oid, latency FROM whitelist WHERE (id == ?);";
- struct sqlite3_stmt *stmt_wl;
- struct WhiteListRow *lr;
- int nrows;
- int ret;
- if (SQLITE_OK != (ret = sqlite3_prepare_v2 (db, query_wl, -1, &stmt_wl,
- NULL)))
- {
- LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
- return GNUNET_SYSERR;
- }
- if (SQLITE_OK != (ret = sqlite3_bind_int (stmt_wl, 1, pid)))
- {
- LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
- sqlite3_finalize (stmt_wl);
- return GNUNET_SYSERR;
- }
- nrows = 0;
- do
- {
- ret = sqlite3_step (stmt_wl);
- if (SQLITE_ROW != ret)
- break;
- nrows++;
- lr = GNUNET_new (struct WhiteListRow);
- lr->id = sqlite3_column_int (stmt_wl, 0);
- lr->latency = sqlite3_column_int (stmt_wl, 1);
- lr->next = *wl_rows;
- *wl_rows = lr;
- }
- while (1);
- sqlite3_finalize (stmt_wl);
- return nrows;
- }
- /**
- * Main function that will be run.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
- */
- static void
- run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
- {
- char *dbfile;
- struct WhiteListRow *wl_head;
- struct WhiteListRow *wl_entry;
- struct GNUNET_PeerIdentity identity;
- struct GNUNET_ATS_Properties prop;
- struct GNUNET_TIME_Relative delay;
- unsigned long long pid;
- unsigned int nrows;
- int ret;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "TESTBED",
- "PEERID", &pid))
- {
- GNUNET_break (0);
- return;
- }
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
- "TESTBED-UNDERLAY",
- "DBFILE",
- &dbfile))
- {
- GNUNET_break (0);
- return;
- }
- if (SQLITE_OK != (ret = sqlite3_open_v2 (dbfile, &db, SQLITE_OPEN_READONLY,
- NULL)))
- {
- if (NULL != db)
- {
- LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
- GNUNET_break (SQLITE_OK == sqlite3_close (db));
- }
- else
- LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
- GNUNET_free (dbfile);
- return;
- }
- DEBUG ("Opened database %s\n", dbfile);
- GNUNET_free (dbfile);
- dbfile = NULL;
- wl_head = NULL;
- if (GNUNET_OK != load_keys (c))
- goto close_db;
- transport = GNUNET_TRANSPORT_manipulation_connect (c);
- if (NULL == transport)
- {
- GNUNET_break (0);
- return;
- }
- /* read and process whitelist */
- nrows = 0;
- wl_head = NULL;
- nrows = db_read_whitelist (db, pid, &wl_head);
- if ((GNUNET_SYSERR == nrows) || (0 == nrows))
- {
- GNUNET_TRANSPORT_manipulation_disconnect (transport);
- goto close_db;
- }
- map = GNUNET_CONTAINER_multipeermap_create (nrows, GNUNET_NO);
- while (NULL != (wl_entry = wl_head))
- {
- wl_head = wl_entry->next;
- delay.rel_value_us = wl_entry->latency;
- memset (&prop, 0, sizeof(prop));
- GNUNET_assert (GNUNET_OK == get_identity (wl_entry->id, &identity));
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (map, &identity, &identity,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
- DEBUG ("Setting %u ms latency to peer `%s'\n",
- wl_entry->latency,
- GNUNET_i2s (&identity));
- GNUNET_TRANSPORT_manipulation_set (transport,
- &identity,
- &prop,
- delay,
- delay);
- GNUNET_free (wl_entry);
- }
- bh = GNUNET_TRANSPORT_blacklist (c, &check_access, NULL);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
- close_db:
- GNUNET_break (SQLITE_OK == sqlite3_close (db));
- }
- /**
- * The main function.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
- int
- main (int argc, char *const *argv)
- {
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
- return 2;
- #ifdef SQLITE_CONFIG_MMAP_SIZE
- (void) sqlite3_config (SQLITE_CONFIG_MMAP_SIZE, 512000, 256000000);
- #endif
- ret =
- (GNUNET_OK ==
- GNUNET_PROGRAM_run (argc, argv, "testbed-underlay",
- _
- (
- "Daemon to restrict underlay network in testbed deployments"),
- options, &run, NULL)) ? 0 : 1;
- GNUNET_free ((void*) argv);
- return ret;
- }
|