plugin_block_regex.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 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 regex/plugin_block_regex.c
  18. * @brief blocks used for regex storage and search
  19. * @author Bartlomiej Polot
  20. */
  21. #include "platform.h"
  22. #include "gnunet_block_plugin.h"
  23. #include "gnunet_block_group_lib.h"
  24. #include "block_regex.h"
  25. #include "regex_block_lib.h"
  26. #include "gnunet_signatures.h"
  27. /**
  28. * Number of bits we set per entry in the bloomfilter.
  29. * Do not change!
  30. */
  31. #define BLOOMFILTER_K 16
  32. /**
  33. * How big is the BF we use for REGEX blocks?
  34. */
  35. #define REGEX_BF_SIZE 8
  36. /**
  37. * Create a new block group.
  38. *
  39. * @param ctx block context in which the block group is created
  40. * @param type type of the block for which we are creating the group
  41. * @param nonce random value used to seed the group creation
  42. * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
  43. * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
  44. * @param va variable arguments specific to @a type
  45. * @return block group handle, NULL if block groups are not supported
  46. * by this @a type of block (this is not an error)
  47. */
  48. static struct GNUNET_BLOCK_Group *
  49. block_plugin_regex_create_group (void *cls,
  50. enum GNUNET_BLOCK_Type type,
  51. uint32_t nonce,
  52. const void *raw_data,
  53. size_t raw_data_size,
  54. va_list va)
  55. {
  56. unsigned int bf_size;
  57. const char *guard;
  58. guard = va_arg (va, const char *);
  59. if (0 == strcmp (guard,
  60. "seen-set-size"))
  61. bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned
  62. int),
  63. BLOOMFILTER_K);
  64. else if (0 == strcmp (guard,
  65. "filter-size"))
  66. bf_size = va_arg (va, unsigned int);
  67. else
  68. {
  69. GNUNET_break (0);
  70. bf_size = REGEX_BF_SIZE;
  71. }
  72. GNUNET_break (NULL == va_arg (va, const char *));
  73. return GNUNET_BLOCK_GROUP_bf_create (cls,
  74. bf_size,
  75. BLOOMFILTER_K,
  76. type,
  77. nonce,
  78. raw_data,
  79. raw_data_size);
  80. }
  81. /**
  82. * Function called to validate a reply or a request of type
  83. * #GNUNET_BLOCK_TYPE_REGEX.
  84. * For request evaluation, pass "NULL" for the reply_block.
  85. * Note that it is assumed that the reply has already been
  86. * matched to the key (and signatures checked) as it would
  87. * be done with the #GNUNET_BLOCK_get_key() function.
  88. *
  89. * @param cls closure
  90. * @param type block type
  91. * @param bg block group to evaluate against
  92. * @param eo control flags
  93. * @param query original query (hash)
  94. * @param xquery extrended query data (can be NULL, depending on type)
  95. * @param xquery_size number of bytes in @a xquery
  96. * @param reply_block response to validate
  97. * @param reply_block_size number of bytes in @a reply_block
  98. * @return characterization of result
  99. */
  100. static enum GNUNET_BLOCK_EvaluationResult
  101. evaluate_block_regex (void *cls,
  102. enum GNUNET_BLOCK_Type type,
  103. struct GNUNET_BLOCK_Group *bg,
  104. enum GNUNET_BLOCK_EvaluationOptions eo,
  105. const struct GNUNET_HashCode *query,
  106. const void *xquery,
  107. size_t xquery_size,
  108. const void *reply_block,
  109. size_t reply_block_size)
  110. {
  111. struct GNUNET_HashCode chash;
  112. if (NULL == reply_block)
  113. {
  114. if (0 != xquery_size)
  115. {
  116. const char *s;
  117. s = (const char *) xquery;
  118. if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
  119. {
  120. GNUNET_break_op (0);
  121. return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
  122. }
  123. }
  124. return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
  125. }
  126. if (0 != xquery_size)
  127. {
  128. const char *s;
  129. s = (const char *) xquery;
  130. if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
  131. {
  132. GNUNET_break_op (0);
  133. return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
  134. }
  135. }
  136. else if (NULL != query)
  137. {
  138. /* xquery is required for regex GETs, at least an empty string */
  139. GNUNET_break_op (0);
  140. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "type %d, query %p, xquery %p\n",
  141. type, query, xquery);
  142. return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
  143. }
  144. switch (REGEX_BLOCK_check (reply_block,
  145. reply_block_size,
  146. query,
  147. xquery))
  148. {
  149. case GNUNET_SYSERR:
  150. GNUNET_break_op (0);
  151. return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  152. case GNUNET_NO:
  153. /* xquery mismatch, can happen */
  154. return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
  155. default:
  156. break;
  157. }
  158. GNUNET_CRYPTO_hash (reply_block,
  159. reply_block_size,
  160. &chash);
  161. if (GNUNET_YES ==
  162. GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
  163. &chash))
  164. return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
  165. return GNUNET_BLOCK_EVALUATION_OK_MORE;
  166. }
  167. /**
  168. * Function called to validate a reply or a request of type
  169. * #GNUNET_BLOCK_TYPE_REGEX_ACCEPT.
  170. * For request evaluation, pass "NULL" for the reply_block.
  171. * Note that it is assumed that the reply has already been
  172. * matched to the key (and signatures checked) as it would
  173. * be done with the #GNUNET_BLOCK_get_key() function.
  174. *
  175. * @param cls closure
  176. * @param type block type
  177. * @param bg block group to evaluate against
  178. * @param eo control flags
  179. * @param query original query (hash)
  180. * @param xquery extrended query data (can be NULL, depending on type)
  181. * @param xquery_size number of bytes in @a xquery
  182. * @param reply_block response to validate
  183. * @param reply_block_size number of bytes in @a reply_block
  184. * @return characterization of result
  185. */
  186. static enum GNUNET_BLOCK_EvaluationResult
  187. evaluate_block_regex_accept (void *cls,
  188. enum GNUNET_BLOCK_Type type,
  189. struct GNUNET_BLOCK_Group *bg,
  190. enum GNUNET_BLOCK_EvaluationOptions eo,
  191. const struct GNUNET_HashCode *query,
  192. const void *xquery,
  193. size_t xquery_size, const void *reply_block,
  194. size_t reply_block_size)
  195. {
  196. const struct RegexAcceptBlock *rba;
  197. struct GNUNET_HashCode chash;
  198. if (0 != xquery_size)
  199. {
  200. GNUNET_break_op (0);
  201. return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
  202. }
  203. if (NULL == reply_block)
  204. return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
  205. if (sizeof(struct RegexAcceptBlock) != reply_block_size)
  206. {
  207. GNUNET_break_op (0);
  208. return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  209. }
  210. rba = reply_block;
  211. if (ntohl (rba->purpose.size) !=
  212. sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
  213. + sizeof(struct GNUNET_TIME_AbsoluteNBO)
  214. + sizeof(struct GNUNET_HashCode))
  215. {
  216. GNUNET_break_op (0);
  217. return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  218. }
  219. if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
  220. rba->expiration_time)).
  221. rel_value_us)
  222. {
  223. /* technically invalid, but can happen without an error, so
  224. we're nice by reporting it as a 'duplicate' */
  225. return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
  226. }
  227. if (GNUNET_OK !=
  228. GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT,
  229. &rba->purpose,
  230. &rba->signature,
  231. &rba->peer.public_key))
  232. {
  233. GNUNET_break_op (0);
  234. return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  235. }
  236. GNUNET_CRYPTO_hash (reply_block,
  237. reply_block_size,
  238. &chash);
  239. if (GNUNET_YES ==
  240. GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
  241. &chash))
  242. return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
  243. return GNUNET_BLOCK_EVALUATION_OK_MORE;
  244. }
  245. /**
  246. * Function called to validate a reply or a request. For
  247. * request evaluation, simply pass "NULL" for the reply_block.
  248. * Note that it is assumed that the reply has already been
  249. * matched to the key (and signatures checked) as it would
  250. * be done with the #GNUNET_BLOCK_get_key() function.
  251. *
  252. * @param cls closure
  253. * @param ctx block context
  254. * @param type block type
  255. * @param bg group to evaluate against
  256. * @param eo control flags
  257. * @param query original query (hash)
  258. * @param xquery extrended query data (can be NULL, depending on type)
  259. * @param xquery_size number of bytes in xquery
  260. * @param reply_block response to validate
  261. * @param reply_block_size number of bytes in reply block
  262. * @return characterization of result
  263. */
  264. static enum GNUNET_BLOCK_EvaluationResult
  265. block_plugin_regex_evaluate (void *cls,
  266. struct GNUNET_BLOCK_Context *ctx,
  267. enum GNUNET_BLOCK_Type type,
  268. struct GNUNET_BLOCK_Group *bg,
  269. enum GNUNET_BLOCK_EvaluationOptions eo,
  270. const struct GNUNET_HashCode *query,
  271. const void *xquery,
  272. size_t xquery_size,
  273. const void *reply_block,
  274. size_t reply_block_size)
  275. {
  276. enum GNUNET_BLOCK_EvaluationResult result;
  277. switch (type)
  278. {
  279. case GNUNET_BLOCK_TYPE_REGEX:
  280. result = evaluate_block_regex (cls,
  281. type,
  282. bg,
  283. eo,
  284. query,
  285. xquery, xquery_size,
  286. reply_block, reply_block_size);
  287. break;
  288. case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
  289. result = evaluate_block_regex_accept (cls,
  290. type,
  291. bg,
  292. eo,
  293. query,
  294. xquery, xquery_size,
  295. reply_block, reply_block_size);
  296. break;
  297. default:
  298. result = GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
  299. }
  300. return result;
  301. }
  302. /**
  303. * Function called to obtain the key for a block.
  304. *
  305. * @param cls closure
  306. * @param type block type
  307. * @param block block to get the key for
  308. * @param block_size number of bytes in @a block
  309. * @param key set to the key (query) for the given block
  310. * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
  311. * (or if extracting a key from a block of this type does not work)
  312. */
  313. static int
  314. block_plugin_regex_get_key (void *cls,
  315. enum GNUNET_BLOCK_Type type,
  316. const void *block,
  317. size_t block_size,
  318. struct GNUNET_HashCode *key)
  319. {
  320. switch (type)
  321. {
  322. case GNUNET_BLOCK_TYPE_REGEX:
  323. if (GNUNET_OK !=
  324. REGEX_BLOCK_get_key (block, block_size,
  325. key))
  326. {
  327. GNUNET_break_op (0);
  328. return GNUNET_NO;
  329. }
  330. return GNUNET_OK;
  331. case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
  332. if (sizeof(struct RegexAcceptBlock) != block_size)
  333. {
  334. GNUNET_break_op (0);
  335. return GNUNET_NO;
  336. }
  337. *key = ((struct RegexAcceptBlock *) block)->key;
  338. return GNUNET_OK;
  339. default:
  340. GNUNET_break (0);
  341. return GNUNET_SYSERR;
  342. }
  343. }
  344. /**
  345. * Entry point for the plugin.
  346. */
  347. void *
  348. libgnunet_plugin_block_regex_init (void *cls)
  349. {
  350. static enum GNUNET_BLOCK_Type types[] = {
  351. GNUNET_BLOCK_TYPE_REGEX,
  352. GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
  353. GNUNET_BLOCK_TYPE_ANY /* end of list */
  354. };
  355. struct GNUNET_BLOCK_PluginFunctions *api;
  356. api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
  357. api->evaluate = &block_plugin_regex_evaluate;
  358. api->get_key = &block_plugin_regex_get_key;
  359. api->create_group = &block_plugin_regex_create_group;
  360. api->types = types;
  361. return api;
  362. }
  363. /**
  364. * Exit point from the plugin.
  365. */
  366. void *
  367. libgnunet_plugin_block_regex_done (void *cls)
  368. {
  369. struct GNUNET_BLOCK_PluginFunctions *api = cls;
  370. GNUNET_free (api);
  371. return NULL;
  372. }
  373. /* end of plugin_block_regex.c */