From 8d8976f00329ec326c4642a113e3767d011c396d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 28 Dec 2021 23:39:36 +0100 Subject: revise block plugin design as per discussion with Martin today (only implemented for GNS) --- src/gns/plugin_block_gns.c | 142 +++++++++++++++++++++++++++++++++++++- src/include/gnunet_block_lib.h | 38 ++++++++++ src/include/gnunet_block_plugin.h | 97 ++++++++++++++++++++++++-- 3 files changed, 268 insertions(+), 9 deletions(-) diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c index 9b58c9034..e85b2e9df 100644 --- a/src/gns/plugin_block_gns.c +++ b/src/gns/plugin_block_gns.c @@ -185,7 +185,7 @@ block_plugin_gns_evaluate (void *cls, * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ -static int +static enum GNUNET_GenericReturnValue block_plugin_gns_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *reply_block, @@ -208,13 +208,148 @@ block_plugin_gns_get_key (void *cls, } + +/** + * Function called to validate a query. + * + * @param cls closure + * @param ctx block context + * @param type block type + * @param query original query (hash) + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in @a xquery + * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not + */ +static enum GNUNET_GenericReturnValue +block_plugin_gns_check_query (void *cls, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_HashCode *query, + const void *xquery, + size_t xquery_size) +{ + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_SYSERR; + if (0 != xquery_size) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +/** + * Function called to validate a block for storage. + * + * @param cls closure + * @param type block type + * @param query key for the block (hash), must match exactly + * @param block block data to validate + * @param block_size number of bytes in @a block + * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not + */ +static enum GNUNET_GenericReturnValue +block_plugin_gns_check_block (void *cls, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_HashCode *query, + const void *block, + size_t block_size) +{ + const struct GNUNET_GNSRECORD_Block *block; + struct GNUNET_HashCode h; + + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_SYSERR; + if (block_size < sizeof(struct GNUNET_GNSRECORD_Block)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + block = reply_block; + if (GNUNET_GNSRECORD_block_get_size (block) > block_size) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + GNUNET_GNSRECORD_query_from_block (block, + &h); + if (0 != GNUNET_memcmp (&h, + query)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_GNSRECORD_block_verify (block)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +/** + * Function called to validate a reply to a request. Note that it is assumed + * that the reply has already been matched to the key (and signatures checked) + * as it would be done with the GetKeyFunction and the + * BlockEvaluationFunction. + * + * @param cls closure + * @param type block type + * @param group which block group to use for evaluation + * @param query original query (hash) + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in @a xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in @a reply_block + * @return characterization of result + */ +static enum GNUNET_BLOCK_ReplyEvaluationResult +block_plugin_gns_check_reply (void *cls, + enum GNUNET_BLOCK_Type type, + struct GNUNET_BLOCK_Group *group, + const struct GNUNET_HashCode *query, + const void *xquery, + size_t xquery_size, + const void *reply_block, + size_t reply_block_size) +{ + const struct GNUNET_GNSRECORD_Block *block; + struct GNUNET_HashCode chash; + + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED; + /* this is a reply */ + if (reply_block_size < sizeof(struct GNUNET_GNSRECORD_Block)) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_REPLY_RESULT_INVALID; + } + block = reply_block; + if (GNUNET_GNSRECORD_block_get_size (block) > reply_block_size) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_REPLY_INVALID; + } + GNUNET_CRYPTO_hash (reply_block, + reply_block_size, + &chash); + if (GNUNET_YES == + GNUNET_BLOCK_GROUP_bf_test_and_set (bg, + &chash)) + return GNUNET_BLOCK_REPLY_OK_DUPLICATE; + return GNUNET_BLOCK_REPLY_OK_MORE; +} + + /** * Entry point for the plugin. */ void * libgnunet_plugin_block_gns_init (void *cls) { - static enum GNUNET_BLOCK_Type types[] = { + static const enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_GNS_NAMERECORD, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; @@ -224,6 +359,9 @@ libgnunet_plugin_block_gns_init (void *cls) api->evaluate = &block_plugin_gns_evaluate; api->get_key = &block_plugin_gns_get_key; api->create_group = &block_plugin_gns_create_group; + api->check_query = &block_plugin_gns_check_query; + api->check_block = &block_plugin_gns_check_block; + api->check_reply = &block_plugin_gns_check_reply; api->types = types; return api; } diff --git a/src/include/gnunet_block_lib.h b/src/include/gnunet_block_lib.h index 341c7bb5c..50306b003 100644 --- a/src/include/gnunet_block_lib.h +++ b/src/include/gnunet_block_lib.h @@ -220,6 +220,44 @@ enum GNUNET_BLOCK_EvaluationResult }; +/** + * Possible ways for how a block may relate to a query. + */ +enum GNUNET_BLOCK_ReplyEvaluationResult +{ + /** + * Valid result, but suppressed because it is a duplicate. + */ + GNUNET_BLOCK_REPLY_OK_DUPLICATE = 0, + + /** + * Valid result, and there may be more. + */ + GNUNET_BLOCK_REPLY_OK_MORE = 1, + + /** + * Last possible valid result. + */ + GNUNET_BLOCK_REPLY_OK_LAST = 2, + + /** + * Specified block type not supported by any plugin. + */ + GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED = -1 + + /** + * Block does not match query (invalid result) + */ + GNUNET_BLOCK_REPLY_INVALID = -2, + + /** + * Block does not match xquery (valid result, not relevant for the request) + */ + GNUNET_BLOCK_REPLY_IRRELEVANT = -3, + +}; + + /** * Handle to an initialized block library. */ diff --git a/src/include/gnunet_block_plugin.h b/src/include/gnunet_block_plugin.h index ee237ac03..2c9a3839d 100644 --- a/src/include/gnunet_block_plugin.h +++ b/src/include/gnunet_block_plugin.h @@ -48,9 +48,9 @@ * @param seen_results_count number of entries in @a seen_results */ typedef void -(*GNUNET_BLOCK_GroupMarkSeenFunction)(struct GNUNET_BLOCK_Group *bg, - const struct - GNUNET_HashCode *seen_results, +(*GNUNET_BLOCK_GroupMarkSeenFunction)( + struct GNUNET_BLOCK_Group *bg, + const struct GNUNET_HashCode *seen_results, unsigned int seen_results_count); @@ -63,7 +63,7 @@ typedef void * @return #GNUNET_OK on success, #GNUNET_NO if the nonces were different and thus * we failed. */ -typedef int +typedef enum GNUNET_GenericReturnValue (*GNUNET_BLOCK_GroupMergeFunction)(struct GNUNET_BLOCK_Group *bg1, const struct GNUNET_BLOCK_Group *bg2); @@ -78,7 +78,7 @@ typedef int * @return #GNUNET_OK on success, #GNUNET_NO if serialization is not * supported, #GNUNET_SYSERR on error */ -typedef int +typedef enum GNUNET_GenericReturnValue (*GNUNET_BLOCK_GroupSerializeFunction)(struct GNUNET_BLOCK_Group *bg, uint32_t *nonce, void **raw_data, @@ -180,6 +180,7 @@ typedef struct GNUNET_BLOCK_Group * * @param reply_block response to validate * @param reply_block_size number of bytes in @a reply_block * @return characterization of result + * @deprecated */ typedef enum GNUNET_BLOCK_EvaluationResult (*GNUNET_BLOCK_EvaluationFunction)(void *cls, @@ -194,6 +195,70 @@ typedef enum GNUNET_BLOCK_EvaluationResult size_t reply_block_size); +/** + * Function called to validate a query. + * + * @param cls closure + * @param ctx block context + * @param type block type + * @param query original query (hash) + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in @a xquery + * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not + */ +typedef enum GNUNET_GenericReturnValue +(*GNUNET_BLOCK_QueryEvaluationFunction)(void *cls, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_HashCode *query, + const void *xquery, + size_t xquery_size); + + +/** + * Function called to validate a block for storage. + * + * @param cls closure + * @param type block type + * @param query key for the block (hash), must match exactly + * @param block block data to validate + * @param block_size number of bytes in @a block + * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not + */ +typedef enum GNUNET_GenericReturnValue +(*GNUNET_BLOCK_BlockEvaluationFunction)(void *cls, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_HashCode *query, + const void *block, + size_t block_size); + + +/** + * Function called to validate a reply to a request. Note that it is assumed + * that the reply has already been matched to the key (and signatures checked) + * as it would be done with the GetKeyFunction and the + * BlockEvaluationFunction. + * + * @param cls closure + * @param type block type + * @param group which block group to use for evaluation + * @param query original query (hash) + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in @a xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in @a reply_block + * @return characterization of result + */ +typedef enum GNUNET_BLOCK_ReplyEvaluationResult +(*GNUNET_BLOCK_ReplyEvaluationFunction)(void *cls, + enum GNUNET_BLOCK_Type type, + struct GNUNET_BLOCK_Group *group, + const struct GNUNET_HashCode *query, + const void *xquery, + size_t xquery_size, + const void *reply_block, + size_t reply_block_size); + + /** * Function called to obtain the key for a block. * @@ -201,13 +266,13 @@ typedef enum GNUNET_BLOCK_EvaluationResult * @param type block type * @param block block to get the key for * @param block_size number of bytes in @a block - * @param key set to the key (query) for the given block + * @param[out] key set to the key (query) for the given block * @return #GNUNET_YES on success, * #GNUNET_NO if the block is malformed * #GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ -typedef int +typedef enum GNUNET_GenericReturnValue (*GNUNET_BLOCK_GetKeyFunction) (void *cls, enum GNUNET_BLOCK_Type type, const void *block, @@ -234,6 +299,8 @@ struct GNUNET_BLOCK_PluginFunctions /** * Main function of a block plugin. Allows us to check if a * block matches a query. + * + * @param deprecated */ GNUNET_BLOCK_EvaluationFunction evaluate; @@ -247,6 +314,22 @@ struct GNUNET_BLOCK_PluginFunctions * context (i.e. to detect duplicates). */ GNUNET_BLOCK_GroupCreateFunction create_group; + + /** + * Check that a query is well-formed. + */ + GNUNET_BLOCK_QueryEvaluationFunction check_query; + + /** + * Check that a block is well-formed. + */ + GNUNET_BLOCK_BlockEvaluationFunction check_block; + + /** + * Check that a reply block matches a query. + */ + GNUNET_BLOCK_ReplyEvaluationFunction check_reply; + }; #endif -- cgit v1.2.3