2 This file is part of GNUnet
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @file testbed/gnunet-daemon-testbed-blacklist.c
24 * @brief daemon to restrict incoming connections from other peers at the
25 * transport layer of a peer
26 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
30 #include "gnunet_util_lib.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_testing_lib.h"
38 #define LOG(type,...) \
39 GNUNET_log (type, __VA_ARGS__)
42 * Debug logging shorthand
45 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
48 #define LOG_SQLITE_ERROR(ret) \
49 LOG (GNUNET_ERROR_TYPE_ERROR, "sqlite error: %s", sqlite3_errstr (ret))
53 * Allow access from the peers read from the whitelist
55 #define ACCESS_ALLOW 1
58 * Deny access from the peers read from the blacklist
63 * The map to store the peer identities to allow/deny
65 static struct GNUNET_CONTAINER_MultiPeerMap *map;
69 * The map to store the peer identities to allow/deny
71 static struct GNUNET_CONTAINER_MultiPeerMap *blacklist_map;
74 * The database connection
76 static struct sqlite3 *db;
79 * The array of peer identities we read from whitelist/blacklist
81 static struct GNUNET_PeerIdentity *ilist;
84 * The blacklist handle we obtain from transport when we register ourselves for
87 struct GNUNET_TRANSPORT_Blacklist *bh;
92 static struct GNUNET_DISK_MapHandle *idmap;
97 static struct GNUNET_PeerIdentity *hostkeys;
100 * The number of hostkeys in the hostkeys array
102 static unsigned int num_hostkeys;
107 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
110 * Are we allowing or denying access from peers
117 * Iterator over hash map entries.
120 * @param key current key code
121 * @param value value in the hash map
122 * @return #GNUNET_YES if we should continue to
127 iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
129 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
136 * Cleaup and destroy the map
143 GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_iterate (map,
146 GNUNET_CONTAINER_multipeermap_destroy (map);
153 * Shutdown task to cleanup our resources and exit.
156 * @param tc scheduler task context
159 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
163 GNUNET_TRANSPORT_blacklist_cancel (bh);
168 * Function that decides if a connection is acceptable or not.
171 * @param pid peer to approve or disapproave
172 * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
175 check_access (void *cls, const struct GNUNET_PeerIdentity * pid)
180 contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
182 contains = GNUNET_NO;
183 if (ACCESS_DENY == mode)
184 return (contains) ? GNUNET_SYSERR : GNUNET_OK;
185 return (contains) ? GNUNET_OK : GNUNET_SYSERR;
190 * Setup the access control by reading the given file containing peer identities
191 * and then establishing blacklist handler with the peer's transport service
193 * @param fname the filename to read the list of peer identities
194 * @param cfg the configuration for connecting to the peer's transport service
197 setup_ac (const char *fname, const struct GNUNET_CONFIGURATION_Handle *cfg)
203 GNUNET_assert (GNUNET_OK != GNUNET_DISK_file_size (fname, &fsize, GNUNET_NO,
205 if (0 != (fsize % sizeof (struct GNUNET_PeerIdentity)))
210 npeers = fsize / sizeof (struct GNUNET_PeerIdentity);
213 map = GNUNET_CONTAINER_multipeermap_create (npeers, GNUNET_YES);
214 ilist = GNUNET_malloc_large (fsize);
215 GNUNET_assert (fsize == GNUNET_DISK_fn_read (fname, ilist, fsize));
217 for (cnt = 0; cnt < npeers; cnt++)
219 if (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put (map, &ilist[cnt],
221 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
228 shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
230 bh = GNUNET_TRANSPORT_blacklist (cfg, &check_access, NULL);
235 * Function to blacklist a peer
237 * @param offset the offset where to find the peer's hostkey in the array of hostkeys
240 blacklist_peer (unsigned int offset)
242 struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
243 struct GNUNET_PeerIdentity id;
245 (void) memcpy (&private_key, &hostkeys[offset], sizeof (private_key));
246 GNUNET_CRYPTO_eddsa_key_get_public (&private_key, &id.public_key);
247 GNUNET_break (GNUNET_OK ==
248 GNUNET_CONTAINER_multipeermap_put (map, &id, &id,
249 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
261 struct ListRow *next;
264 * The offset where to find the hostkey for the peer
271 * Function to add a peer to the blacklist
273 * @param head the head of the list
274 * @param id the id of the peer to add
277 listrow_add (struct ListRow *head, unsigned int id)
281 bp = GNUNET_new (struct ListRow);
289 * Add peers in the blacklist to the blacklist map
292 map_populate (struct ListRow *head,
293 struct GNUNET_CONTAINER_MultiPeerMap *map,
294 const struct GNUNET_PeerIdentity *hostkeys)
299 while (NULL != (row = head))
301 if (head->id >= num_hostkeys)
303 LOG (GNUNET_ERROR_TYPE_WARNING, "Hostkey index %u out of max range %u\n",
304 row->id, num_hostkeys);
307 ret = GNUNET_CONTAINER_multipeermap_put (blacklist_map, &hostkeys[row->id],
308 (void *) &hostkeys[row->id],
309 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
310 if (GNUNET_OK != ret)
311 return GNUNET_SYSERR;
318 * Function to load keys
321 load_keys (const struct GNUNET_CONFIGURATION_Handle *c)
325 struct GNUNET_DISK_FileHandle *fd;
332 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
333 GNUNET_asprintf (&idfile, "%s/testing_hostkeys.ecc", data_dir);
334 GNUNET_free (data_dir);
337 GNUNET_DISK_file_size (idfile, &fsize, GNUNET_YES, GNUNET_YES))
339 GNUNET_free (idfile);
340 return GNUNET_SYSERR;
342 if (0 != (fsize % GNUNET_TESTING_HOSTKEYFILESIZE))
344 LOG (GNUNET_ERROR_TYPE_ERROR,
345 _("Incorrect hostkey file format: %s\n"), idfile);
346 GNUNET_free (idfile);
347 return GNUNET_SYSERR;
349 fd = GNUNET_DISK_file_open (idfile, GNUNET_DISK_OPEN_READ,
350 GNUNET_DISK_PERM_NONE);
353 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", idfile);
354 GNUNET_free (idfile);
355 return GNUNET_SYSERR;
357 GNUNET_free (idfile);
359 hostkeys = (struct GNUNET_PeerIdentity *)
360 GNUNET_DISK_file_map (fd, &idmap, GNUNET_DISK_MAP_TYPE_READ, fsize);
361 if (NULL == hostkeys)
362 num_hostkeys = fsize / GNUNET_TESTING_HOSTKEYFILESIZE;
368 db_read_blacklist (sqlite3 *dbfile, unsigned int pid, struct ListRow **blacklist_rows)
370 static const char *query_bl = "SELECT (id, oid) FROM blacklist WHERE (id == ?);";
371 static struct sqlite3_stmt *stmt_bl;
376 if (SQLITE_OK != (ret = sqlite3_prepare_v2 (db, query_bl, -1, &stmt_bl, NULL)))
378 LOG_SQLITE_ERROR (ret);
379 return GNUNET_SYSERR;
381 if (SQLITE_OK != (ret = sqlite3_bind_int (stmt_bl, 1, pid)))
383 LOG_SQLITE_ERROR (ret);
384 sqlite3_finalize (stmt_bl);
385 return GNUNET_SYSERR;
390 ret = sqlite3_step (stmt_bl);
391 if (SQLITE_ROW != ret)
393 peer_id = sqlite3_column_int (stmt_bl, 1);
394 listrow_add (*blacklist_rows, peer_id);
397 sqlite3_finalize (stmt_bl);
404 * Main function that will be run.
407 * @param args remaining command-line arguments
408 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
409 * @param c configuration
412 run (void *cls, char *const *args, const char *cfgfile,
413 const struct GNUNET_CONFIGURATION_Handle *c)
416 struct ListRow *blacklist_rows;
417 unsigned long long pid;
421 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c, "TESTBED",
427 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "TESTBED",
434 if (SQLITE_OK != (ret = sqlite3_open_v2 (dbfile, &db, SQLITE_OPEN_READONLY, NULL)))
436 LOG_SQLITE_ERROR (ret);
437 GNUNET_free (dbfile);
440 DEBUG ("Opened database %s\n", dbfile);
441 GNUNET_free (dbfile);
443 blacklist_rows = NULL;
444 nrows = db_read_blacklist (db, pid, &blacklist_rows);
449 blacklist_map = GNUNET_CONTAINER_multipeermap_create (nrows, GNUNET_YES);
450 if (GNUNET_OK != load_keys (c))
455 /* process whitelist */
456 GNUNET_break (0); /* TODO */
459 GNUNET_break (GNUNET_OK == sqlite3_close (db));
467 * @param argc number of arguments from the command line
468 * @param argv command line arguments
469 * @return 0 ok, 1 on error
472 main (int argc, char *const *argv)
474 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
475 GNUNET_GETOPT_OPTION_END
479 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
481 #ifdef SQLITE_CONFIG_MMAP_SIZE
482 (void) sqlite3_config (SQLITE_CONFIG_MMAP_SIZE, 512000, 256000000);
486 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-testbed-underlay",
488 ("Daemon to restrict underlay network in testbed deployments"),
489 options, &run, NULL)) ? 0 : 1;
490 GNUNET_free ((void*) argv);