last XDG change: use GNUNET_RUNTIME_DIR instead of /tmp for UNIXPATHs by default
[oweals/gnunet.git] / src / regex / plugin_block_regex.c
1 /*
2      This file is part of GNUnet
3      (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file regex/plugin_block_regex.c
23  * @brief blocks used for regex storage and search
24  * @author Bartlomiej Polot
25  */
26
27 #include "platform.h"
28 #include "gnunet_block_plugin.h"
29 #include "block_regex.h"
30 #include "regex_block_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_signatures.h"
33
34
35 /**
36  * Function called to validate a reply or a request of type
37  * GNUNET_BLOCK_TYPE_REGEX.
38  * For request evaluation, pass "NULL" for the reply_block.
39  * Note that it is assumed that the reply has already been
40  * matched to the key (and signatures checked) as it would
41  * be done with the "get_key" function.
42  *
43  * @param cls closure
44  * @param type block type
45  * @param query original query (hash)
46  * @param bf pointer to bloom filter associated with query; possibly updated (!)
47  * @param bf_mutator mutation value for bf
48  * @param xquery extrended query data (can be NULL, depending on type)
49  * @param xquery_size number of bytes in xquery
50  * @param reply_block response to validate
51  * @param reply_block_size number of bytes in reply block
52  * @return characterization of result
53  */
54 static enum GNUNET_BLOCK_EvaluationResult
55 evaluate_block_regex (void *cls, enum GNUNET_BLOCK_Type type,
56                       const struct GNUNET_HashCode *query,
57                       struct GNUNET_CONTAINER_BloomFilter **bf,
58                       int32_t bf_mutator, const void *xquery,
59                       size_t xquery_size, const void *reply_block,
60                       size_t reply_block_size)
61 {
62   if (NULL == reply_block)
63   {
64     if (0 != xquery_size)
65       {
66         const char *s;
67
68         s = (const char *) xquery;
69         if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
70           {
71             GNUNET_break_op (0);
72             return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
73           }
74       }
75     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
76   }
77   if (0 != xquery_size)
78   {
79     const char *s;
80
81     s = (const char *) xquery;
82     if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
83     {
84       GNUNET_break_op (0);
85       return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
86     }
87   }
88   else if (NULL != query)
89   {
90     /* xquery is required for regex GETs, at least an empty string */
91     GNUNET_break_op (0);
92     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "type %d, query %p, xquery %p\n",
93                 type, query, xquery);
94     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
95   }
96   switch (REGEX_BLOCK_check (reply_block,
97                              reply_block_size,
98                              query,
99                              xquery))
100   {
101     case GNUNET_SYSERR:
102       GNUNET_break_op(0);
103       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
104     case GNUNET_NO:
105       /* xquery missmatch, can happen */
106       return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
107     default:
108       break;
109   }
110   if (NULL != bf)
111   {
112     struct GNUNET_HashCode chash;
113     struct GNUNET_HashCode mhash;
114
115     GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
116     GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
117     if (NULL != *bf)
118     {
119       if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
120         return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
121     }
122     else
123     {
124       *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
125     }
126     GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
127   }
128   return GNUNET_BLOCK_EVALUATION_OK_MORE;
129 }
130
131
132 /**
133  * Function called to validate a reply or a request of type
134  * GNUNET_BLOCK_TYPE_REGEX_ACCEPT.
135  * For request evaluation, pass "NULL" for the reply_block.
136  * Note that it is assumed that the reply has already been
137  * matched to the key (and signatures checked) as it would
138  * be done with the "get_key" function.
139  *
140  * @param cls closure
141  * @param type block type
142  * @param query original query (hash)
143  * @param bf pointer to bloom filter associated with query; possibly updated (!)
144  * @param bf_mutator mutation value for bf
145  * @param xquery extrended query data (can be NULL, depending on type)
146  * @param xquery_size number of bytes in xquery
147  * @param reply_block response to validate
148  * @param reply_block_size number of bytes in reply block
149  * @return characterization of result
150  */
151 static enum GNUNET_BLOCK_EvaluationResult
152 evaluate_block_regex_accept (void *cls, enum GNUNET_BLOCK_Type type,
153                              const struct GNUNET_HashCode * query,
154                              struct GNUNET_CONTAINER_BloomFilter **bf,
155                              int32_t bf_mutator, const void *xquery,
156                              size_t xquery_size, const void *reply_block,
157                              size_t reply_block_size)
158 {
159   const struct RegexAcceptBlock *rba;
160
161   if (0 != xquery_size)
162   {
163     GNUNET_break_op (0);
164     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
165   }
166   if (NULL == reply_block)
167     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
168   if (sizeof (struct RegexAcceptBlock) != reply_block_size)
169   {
170     GNUNET_break_op(0);
171     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
172   }
173   rba = reply_block;
174   if (ntohl (rba->purpose.size) !=
175       sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
176       sizeof (struct GNUNET_TIME_AbsoluteNBO) +
177       sizeof (struct GNUNET_HashCode))
178   {
179     GNUNET_break_op(0);
180     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
181   }
182   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (rba->expiration_time)).rel_value_us)
183   {
184     /* technically invalid, but can happen without an error, so
185        we're nice by reporting it as a 'duplicate' */
186     return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
187   }
188   if (GNUNET_OK !=
189       GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT,
190                                 &rba->purpose,
191                                 &rba->signature,
192                                 &rba->peer.public_key))
193   {
194     GNUNET_break_op(0);
195     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
196   }
197   if (NULL != bf)
198   {
199     struct GNUNET_HashCode chash;
200     struct GNUNET_HashCode mhash;
201
202     GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
203     GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
204     if (NULL != *bf)
205     {
206       if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
207         return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
208     }
209     else
210     {
211       *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
212     }
213     GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
214   }
215   return GNUNET_BLOCK_EVALUATION_OK_MORE;
216 }
217
218
219 /**
220  * Function called to validate a reply or a request.  For
221  * request evaluation, simply pass "NULL" for the reply_block.
222  * Note that it is assumed that the reply has already been
223  * matched to the key (and signatures checked) as it would
224  * be done with the "get_key" function.
225  *
226  * @param cls closure
227  * @param type block type
228  * @param query original query (hash)
229  * @param bf pointer to bloom filter associated with query; possibly updated (!)
230  * @param bf_mutator mutation value for bf
231  * @param xquery extrended query data (can be NULL, depending on type)
232  * @param xquery_size number of bytes in xquery
233  * @param reply_block response to validate
234  * @param reply_block_size number of bytes in reply block
235  * @return characterization of result
236  */
237 static enum GNUNET_BLOCK_EvaluationResult
238 block_plugin_regex_evaluate (void *cls, enum GNUNET_BLOCK_Type type,
239                              const struct GNUNET_HashCode * query,
240                              struct GNUNET_CONTAINER_BloomFilter **bf,
241                              int32_t bf_mutator, const void *xquery,
242                              size_t xquery_size, const void *reply_block,
243                              size_t reply_block_size)
244 {
245   enum GNUNET_BLOCK_EvaluationResult result;
246
247   switch (type)
248   {
249     case GNUNET_BLOCK_TYPE_REGEX:
250       result = evaluate_block_regex (cls, type, query, bf, bf_mutator,
251                                      xquery, xquery_size,
252                                      reply_block, reply_block_size);
253       break;
254     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
255       result = evaluate_block_regex_accept (cls, type, query, bf, bf_mutator,
256                                             xquery, xquery_size,
257                                             reply_block, reply_block_size);
258       break;
259
260     default:
261       result = GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
262   }
263   return result;
264 }
265
266
267 /**
268  * Function called to obtain the key for a block.
269  *
270  * @param cls closure
271  * @param type block type
272  * @param block block to get the key for
273  * @param block_size number of bytes in block
274  * @param key set to the key (query) for the given block
275  * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
276  *         (or if extracting a key from a block of this type does not work)
277  */
278 static int
279 block_plugin_regex_get_key (void *cls, enum GNUNET_BLOCK_Type type,
280                             const void *block, size_t block_size,
281                             struct GNUNET_HashCode * key)
282 {
283   switch (type)
284   {
285     case GNUNET_BLOCK_TYPE_REGEX:
286       if (GNUNET_OK !=
287           REGEX_BLOCK_get_key (block, block_size,
288                                key))
289       {
290         GNUNET_break_op (0);
291         return GNUNET_NO;
292       }
293       return GNUNET_OK;
294     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
295       if (sizeof (struct RegexAcceptBlock) != block_size)
296       {
297         GNUNET_break_op (0);
298         return GNUNET_NO;
299       }
300       *key = ((struct RegexAcceptBlock *) block)->key;
301       return GNUNET_OK;
302     default:
303       GNUNET_break (0);
304       return GNUNET_SYSERR;
305   }
306 }
307
308
309 /**
310  * Entry point for the plugin.
311  */
312 void *
313 libgnunet_plugin_block_regex_init (void *cls)
314 {
315   static enum GNUNET_BLOCK_Type types[] =
316   {
317     GNUNET_BLOCK_TYPE_REGEX,
318     GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
319     GNUNET_BLOCK_TYPE_ANY       /* end of list */
320   };
321   struct GNUNET_BLOCK_PluginFunctions *api;
322
323   api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions));
324   api->evaluate = &block_plugin_regex_evaluate;
325   api->get_key = &block_plugin_regex_get_key;
326   api->types = types;
327   return api;
328 }
329
330
331 /**
332  * Exit point from the plugin.
333  */
334 void *
335 libgnunet_plugin_block_regex_done (void *cls)
336 {
337   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
338
339   GNUNET_free (api);
340   return NULL;
341 }
342
343 /* end of plugin_block_regex.c */