small API change: do no longer pass rarely needed GNUNET_SCHEDULER_TaskContext to...
[oweals/gnunet.git] / src / testbed / gnunet-daemon-testbed-blacklist.c
1 /*
2       This file is part of GNUnet
3       Copyright (C) 2008--2013 GNUnet e.V.
4
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.
9
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.
14
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., 51 Franklin Street, Fifth Floor,
18       Boston, MA 02110-1301, USA.
19 */
20
21
22 /**
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>
27  */
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_transport_service.h"
32
33
34 /**
35  * Logging shorthand
36  */
37 #define LOG(type,...)                           \
38   GNUNET_log (type, __VA_ARGS__)
39
40 /**
41  * Debug logging shorthand
42  */
43 #define DEBUG(...)                              \
44   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
45
46 /**
47  * Allow access from the peers read from the whitelist
48  */
49 #define ACCESS_ALLOW 1
50
51 /**
52  * Deny access from the peers read from the blacklist
53  */
54 #define ACCESS_DENY 0
55
56 /**
57  * The map to store the peer identities to allow/deny
58  */
59 static struct GNUNET_CONTAINER_MultiPeerMap *map;
60
61 /**
62  * The array of peer identities we read from whitelist/blacklist
63  */
64 static struct GNUNET_PeerIdentity *ilist;
65
66 /**
67  * The blacklist handle we obtain from transport when we register ourselves for
68  * access control
69  */
70 struct GNUNET_TRANSPORT_Blacklist *bh;
71
72 /**
73  * Task for shutdown
74  */
75 static struct GNUNET_SCHEDULER_Task * shutdown_task;
76
77 /**
78  * Are we allowing or denying access from peers
79  */
80 static int mode;
81
82
83 /**
84  * @ingroup hashmap
85  * Iterator over hash map entries.
86  *
87  * @param cls closure
88  * @param key current key code
89  * @param value value in the hash map
90  * @return #GNUNET_YES if we should continue to
91  *         iterate,
92  *         #GNUNET_NO if not.
93  */
94 static int
95 iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
96 {
97   GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
98                                                                      value));
99   return GNUNET_YES;
100 }
101
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
120 /**
121  * Shutdown task to cleanup our resources and exit.
122  *
123  * @param cls NULL
124  */
125 static void
126 do_shutdown (void *cls)
127 {
128   cleanup_map ();
129   if (NULL != bh)
130     GNUNET_TRANSPORT_blacklist_cancel (bh);
131 }
132
133
134 /**
135  * Function that decides if a connection is acceptable or not.
136  *
137  * @param cls closure
138  * @param pid peer to approve or disapproave
139  * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
140  */
141 static int
142 check_access (void *cls, const struct GNUNET_PeerIdentity * pid)
143 {
144   int contains;
145
146   if (NULL != map)
147     contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
148   else
149     contains = GNUNET_NO;
150   if (ACCESS_DENY == mode)
151     return (contains) ? GNUNET_SYSERR : GNUNET_OK;
152   return (contains) ? GNUNET_OK : GNUNET_SYSERR;
153 }
154
155
156 /**
157  * Setup the access control by reading the given file containing peer identities
158  * and then establishing blacklist handler with the peer's transport service
159  *
160  * @param fname the filename to read the list of peer identities
161  * @param cfg the configuration for connecting to the peer's transport service
162  */
163 static void
164 setup_ac (const char *fname, const struct GNUNET_CONFIGURATION_Handle *cfg)
165 {
166   uint64_t fsize;
167   unsigned int npeers;
168   unsigned int cnt;
169
170   GNUNET_assert (GNUNET_OK != GNUNET_DISK_file_size (fname, &fsize, GNUNET_NO,
171                                                      GNUNET_YES));
172   if (0 != (fsize % sizeof (struct GNUNET_PeerIdentity)))
173   {
174     GNUNET_break (0);
175     return;
176   }
177   npeers = fsize / sizeof (struct GNUNET_PeerIdentity);
178   if (0 != npeers)
179   {
180     map = GNUNET_CONTAINER_multipeermap_create (npeers, GNUNET_YES);
181     ilist = GNUNET_malloc_large (fsize);
182     GNUNET_assert (fsize == GNUNET_DISK_fn_read (fname, ilist, fsize));
183   }
184   for (cnt = 0; cnt < npeers; cnt++)
185   {
186     if (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put (map, &ilist[cnt],
187                                                             &ilist[cnt],
188                                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
189     {
190       cleanup_map ();
191       GNUNET_free (ilist);
192       return;
193     }
194   }
195   shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
196                                                 &do_shutdown, NULL);
197   bh = GNUNET_TRANSPORT_blacklist (cfg, &check_access, NULL);
198 }
199
200
201 /**
202  * Main function that will be run.
203  *
204  * @param cls closure
205  * @param args remaining command-line arguments
206  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
207  * @param c configuration
208  */
209 static void
210 run (void *cls, char *const *args, const char *cfgfile,
211      const struct GNUNET_CONFIGURATION_Handle *c)
212 {
213   char *shome;
214   char *fname;
215
216   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "PATHS",
217                                                             "GNUNET_HOME",
218                                                             &shome))
219   {
220     GNUNET_break (0);
221     return;
222   }
223   GNUNET_asprintf (&fname,
224                    "%s/whitelist",
225                    shome);
226   if (GNUNET_YES == GNUNET_DISK_file_test (fname))
227   {
228     mode = ACCESS_ALLOW;
229     setup_ac (fname, c);
230     GNUNET_free (shome);
231     GNUNET_free (fname);
232     return;
233   }
234   GNUNET_asprintf (&fname,
235                    "%s/blacklist",
236                    shome);
237   GNUNET_free (fname);
238   if (GNUNET_YES == GNUNET_DISK_file_test (fname))
239   {
240     mode = ACCESS_DENY;
241     setup_ac (shome, c);
242   }
243   GNUNET_free (shome);
244   return;
245 }
246
247
248 /**
249  * The main function.
250  *
251  * @param argc number of arguments from the command line
252  * @param argv command line arguments
253  * @return 0 ok, 1 on error
254  */
255 int
256 main (int argc, char *const *argv)
257 {
258   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
259     GNUNET_GETOPT_OPTION_END
260   };
261   int ret;
262
263   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
264     return 2;
265   ret =
266       (GNUNET_OK ==
267        GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-testbed-blacklist",
268                            _
269                            ("Daemon to restrict incoming transport layer connections during testbed deployments"),
270                            options, &run, NULL)) ? 0 : 1;
271   GNUNET_free ((void*) argv);
272   return ret;
273 }