GNUnet 0.21.1
pabc_plugin.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
26#include "platform.h"
27#include "microhttpd.h"
28#include <inttypes.h>
29#include <jansson.h>
30#include <pabc/pabc.h>
31#include "gnunet_reclaim_lib.h"
33#include "gnunet_rest_lib.h"
34#include "gnunet_rest_plugin.h"
35#include "gnunet_signatures.h"
36#include "pabc_helper.h"
37
41#define GNUNET_REST_API_NS_PABC "/pabc"
42
46#define GNUNET_REST_API_NS_PABC_CR "/pabc/cr"
47
52
56static char *allow_methods;
57
61struct Plugin
62{
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64};
65
66
67struct RequestHandle
68{
72 struct RequestHandle *next;
73
77 struct RequestHandle *prev;
78
83
88
93
98
102 void *proc_cls;
103
107 char *url;
108
112 char *emsg;
113
117 int response_code;
118
122 json_t *resp_object;
123};
124
129
134
135
140static void
141cleanup_handle (void *cls)
142{
143 struct RequestHandle *handle = cls;
144
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
146 if (NULL != handle->resp_object)
147 json_decref (handle->resp_object);
148 if (NULL != handle->timeout_task)
149 GNUNET_SCHEDULER_cancel (handle->timeout_task);
150 if (NULL != handle->url)
151 GNUNET_free (handle->url);
152 if (NULL != handle->emsg)
153 GNUNET_free (handle->emsg);
156 handle);
158}
159
160
166static void
167do_error (void *cls)
168{
169 struct RequestHandle *handle = cls;
170 struct MHD_Response *resp;
171 char *json_error;
172
173 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
174 if (0 == handle->response_code)
175 {
176 handle->response_code = MHD_HTTP_BAD_REQUEST;
177 }
178 resp = GNUNET_REST_create_response (json_error);
179 MHD_add_response_header (resp, "Content-Type", "application/json");
180 handle->proc (handle->proc_cls, resp, handle->response_code);
182 GNUNET_free (json_error);
183}
184
185
191static void
192do_timeout (void *cls)
193{
194 struct RequestHandle *handle = cls;
195
196 handle->timeout_task = NULL;
198}
199
200
201static void
203{
204 char *result_str;
205 struct RequestHandle *handle = cls;
206 struct MHD_Response *resp;
207
208 result_str = json_dumps (handle->resp_object, 0);
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
210 resp = GNUNET_REST_create_response (result_str);
211 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
212 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
213 GNUNET_free (result_str);
215}
216
217
218static enum pabc_status
219set_attributes_from_idtoken (const struct pabc_context *ctx,
220 const struct pabc_public_parameters *pp,
221 struct pabc_user_context *usr_ctx,
222 const char *id_token)
223{
224 json_t *payload_json;
225 json_t *value;
226 json_error_t json_err;
227 const char *key;
228 const char *jwt_body;
229 char *decoded_jwt;
230 char delim[] = ".";
231 char *jwt_string;
232 const char *pabc_key;
233 enum pabc_status status;
234
235 // FIXME parse JWT
236 jwt_string = GNUNET_strndup (id_token, strlen (id_token));
237 jwt_body = strtok (jwt_string, delim);
238 jwt_body = strtok (NULL, delim);
239 GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
240 (void **) &decoded_jwt);
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decoded ID Token: %s\n", decoded_jwt);
242 payload_json = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
243 GNUNET_free (decoded_jwt);
244
245 json_object_foreach (payload_json, key, value)
246 {
247 pabc_key = key;
248 if (0 == strcmp ("iss", key))
249 pabc_key = "issuer"; // rename
250 if (0 == strcmp ("sub", key))
251 pabc_key = "subject"; // rename
252 if (0 == strcmp ("jti", key))
253 continue;
254 if (0 == strcmp ("exp", key))
255 pabc_key = "expiration"; // rename
256 if (0 == strcmp ("iat", key))
257 continue;
258 if (0 == strcmp ("nbf", key))
259 continue;
260 if (0 == strcmp ("aud", key))
261 continue;
262 char *tmp_val;
263 if (json_is_string (value))
264 tmp_val = GNUNET_strdup (json_string_value (value));
265 else
266 tmp_val = json_dumps (value, JSON_ENCODE_ANY);
267 if (NULL == tmp_val)
268 {
270 "Unable to encode JSON value for `%s'\n", key);
271 continue;
272 }
274 "Setting `%s' to `%s'\n", key, tmp_val);
275 status = pabc_set_attribute_value_by_name (ctx, pp, usr_ctx,
276 pabc_key,
277 tmp_val);
278 GNUNET_free (tmp_val);
279 if (PABC_OK != status)
280 {
282 "Failed to set attribute `%s'.\n", key);
283 }
284 }
285 GNUNET_free (jwt_string);
286 return PABC_OK;
287}
288
289
291setup_new_user_context (struct pabc_context *ctx,
292 struct pabc_public_parameters *pp,
293 struct pabc_user_context **usr_ctx)
294{
295 if (PABC_OK != pabc_new_user_context (ctx, pp, usr_ctx))
296 return GNUNET_SYSERR;
297
298 if (PABC_OK != pabc_populate_user_context (ctx, *usr_ctx))
299 {
300 pabc_free_user_context (ctx, pp, usr_ctx);
301 return GNUNET_SYSERR;
302 }
303 return GNUNET_OK;
304}
305
306
307static void
309 const char *url,
310 void *cls)
311{
312 struct RequestHandle *handle = cls;
313 char term_data[handle->rest_handle->data_size + 1];
314 char *response_str;
315 json_t *data_json;
316 json_t *nonce_json;
317 json_t *pp_json;
318 json_t *idtoken_json;
319 json_t *iss_json;
320 json_t *identity_json;
321 json_error_t err;
322 struct pabc_public_parameters *pp = NULL;
323 struct pabc_context *ctx = NULL;
324 struct pabc_user_context *usr_ctx = NULL;
325 struct pabc_credential_request *cr = NULL;
326 struct pabc_nonce *nonce = NULL;
327 enum pabc_status status;
328
329
331 "Credential request...\n");
332
333 if (0 >= handle->rest_handle->data_size)
334 {
336 return;
337 }
338
339 term_data[handle->rest_handle->data_size] = '\0';
340 GNUNET_memcpy (term_data,
341 handle->rest_handle->data,
342 handle->rest_handle->data_size);
343 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
344 if (NULL == data_json)
345 {
347 "Unable to parse %s\n", term_data);
349 return;
350 }
351 if (! json_is_object (data_json))
352 {
354 "Unable to parse %s\n", term_data);
355 json_decref (data_json);
357 return;
358 }
359
360 nonce_json = json_object_get (data_json, "nonce");
361 if (NULL == nonce_json)
362 {
364 "Unable to parse nonce\n");
365 json_decref (data_json);
367 return;
368 }
369 iss_json = json_object_get (data_json, "issuer");
370 if (NULL == iss_json)
371 {
373 "Unable to parse issuer\n");
374 json_decref (data_json);
376 return;
377 }
378 identity_json = json_object_get (data_json, "identity");
379 if (NULL == identity_json)
380 {
382 "Unable to parse identity\n");
383 json_decref (data_json);
385 return;
386 }
387 idtoken_json = json_object_get (data_json, "id_token");
388 if (NULL == idtoken_json)
389 {
391 "Unable to parse id_token\n");
392 json_decref (data_json);
394 return;
395 }
396 pp_json = json_object_get (data_json, "public_params");
397 if (NULL == pp_json)
398 {
400 "Unable to parse public parameters\n");
401 json_decref (data_json);
403 return;
404 }
405
406 PABC_ASSERT (pabc_new_ctx (&ctx));
407 char *pp_str = json_dumps (pp_json, JSON_ENCODE_ANY);
408 status = pabc_decode_and_new_public_parameters (ctx,
409 &pp,
410 pp_str);
411 char *ppid;
412 GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_pp (pp_str, &ppid));
413 GNUNET_free (pp_str);
414 if (status != PABC_OK)
415 {
417 "Failed to read public parameters: %s\n",
418 pp_str);
419 json_decref (data_json);
421 return;
422 }
423 // (Over)write parameters
424 status = PABC_write_public_parameters (json_string_value (iss_json),
425 pp);
426 if (status != PABC_OK)
427 {
429 "Failed to write public parameters.\n");
430 json_decref (data_json);
432 return;
433 }
434 status = PABC_read_usr_ctx (json_string_value (identity_json),
435 json_string_value (iss_json),
436 ctx, pp, &usr_ctx);
437 if (PABC_OK != status)
438 {
439 if (GNUNET_OK != setup_new_user_context (ctx, pp, &usr_ctx))
440 {
441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup user context.\n");
442 pabc_free_public_parameters (ctx, &pp);
443 json_decref (data_json);
445 return;
446 }
447 PABC_write_usr_ctx (json_string_value (identity_json),
448 json_string_value (iss_json),
449 ctx, pp, usr_ctx);
450 }
451
452 // Set attributes from JWT to context
454 pp,
455 usr_ctx,
456 json_string_value (idtoken_json));
457 if (status != PABC_OK)
458 {
459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to set attributes.\n");
460 pabc_free_user_context (ctx, pp, &usr_ctx);
461 pabc_free_public_parameters (ctx, &pp);
462 json_decref (data_json);
464 return;
465 }
466
467
468 // nonce
469 status = pabc_new_nonce (ctx, &nonce);
470 if (status != PABC_OK)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate nonce.\n");
473 pabc_free_user_context (ctx, pp, &usr_ctx);
474 pabc_free_public_parameters (ctx, &pp);
475 json_decref (data_json);
477 return;
478 }
479 char *nonce_str = json_dumps (nonce_json, JSON_ENCODE_ANY);
480 status = pabc_decode_nonce (ctx, nonce, nonce_str);
481 if (status != PABC_OK)
482 {
483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode nonce.\n");
484 pabc_free_nonce (ctx, &nonce);
485 pabc_free_user_context (ctx, pp, &usr_ctx);
486 pabc_free_public_parameters (ctx, &pp);
487 json_decref (data_json);
489 return;
490 }
491
492 // cr
493 status = pabc_new_credential_request (ctx, pp, &cr);
494 if (PABC_OK != status)
495 {
496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate cr.\n");
497 pabc_free_nonce (ctx, &nonce);
498 pabc_free_user_context (ctx, pp, &usr_ctx);
499 pabc_free_public_parameters (ctx, &pp);
500 json_decref (data_json);
502 return;
503 }
504
505 status = pabc_gen_credential_request (ctx, pp, usr_ctx, nonce, cr);
506 if (PABC_OK != status)
507 {
508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to generate cr.\n");
509 pabc_free_nonce (ctx, &nonce);
510 pabc_free_credential_request (ctx, pp, &cr);
511 pabc_free_user_context (ctx, pp, &usr_ctx);
512 pabc_free_public_parameters (ctx, &pp);
513 json_decref (data_json);
515 return;
516 }
517 handle->resp_object = json_object ();
518 GNUNET_assert (PABC_OK == pabc_cred_encode_cr (ctx, pp, cr,
519 json_string_value (
520 identity_json),
521 ppid, &response_str));
522 if (PABC_OK != status)
523 {
524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize cr.\n");
525 pabc_free_nonce (ctx, &nonce);
526 pabc_free_credential_request (ctx, pp, &cr);
527 pabc_free_user_context (ctx, pp, &usr_ctx);
528 pabc_free_public_parameters (ctx, &pp);
529 json_decref (data_json);
531 return;
532 }
533 json_decref (handle->resp_object);
534 handle->resp_object = json_loads (response_str, JSON_DECODE_ANY, &err);
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", response_str);
536 GNUNET_free (response_str);
537
538 // clean up
539 pabc_free_nonce (ctx, &nonce);
540 pabc_free_credential_request (ctx, pp, &cr);
541 pabc_free_user_context (ctx, pp, &usr_ctx);
542 pabc_free_public_parameters (ctx, &pp);
544 json_decref (data_json);
545}
546
547
555static void
557 const char *url,
558 void *cls)
559{
560 struct MHD_Response *resp;
561 struct RequestHandle *handle = cls;
562
563 // For now, independent of path return all options
564 resp = GNUNET_REST_create_response (NULL);
565 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
566 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
568 return;
569}
570
571
575 void *proc_cls)
576{
577 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
579 static const struct GNUNET_REST_RequestHandler handlers[] = {
580 {MHD_HTTP_METHOD_POST,
582 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PABC, &options_cont },
584 };
585
586 handle->response_code = 0;
588 handle->proc_cls = proc_cls;
589 handle->proc = proc;
590 handle->rest_handle = rest_handle;
591
592 handle->url = GNUNET_strdup (rest_handle->url);
593 if (handle->url[strlen (handle->url) - 1] == '/')
594 handle->url[strlen (handle->url) - 1] = '\0';
595 handle->timeout_task =
599 handle);
600 if (GNUNET_NO ==
601 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
602 {
604 return GNUNET_NO;
605 }
606
607 return GNUNET_YES;
608}
609
610
617void *
619{
620 static struct Plugin plugin;
621 struct GNUNET_REST_Plugin *api;
622
623 cfg = cls;
624 if (NULL != plugin.cfg)
625 return NULL; /* can only initialize once! */
626 memset (&plugin, 0, sizeof(struct Plugin));
627 plugin.cfg = cfg;
628 api = GNUNET_new (struct GNUNET_REST_Plugin);
629 api->cls = &plugin;
631 api->process_request = &rest_identity_process_request;
633 "%s, %s",
634 MHD_HTTP_METHOD_POST,
635 MHD_HTTP_METHOD_OPTIONS);
637 _ ("Identity Provider REST API initialized\n"));
638 return api;
639}
640
641
648void *
650{
651 struct GNUNET_REST_Plugin *api = cls;
652 struct Plugin *plugin = api->cls;
653 struct RequestHandle *request;
654
655 plugin->cfg = NULL;
656 while (NULL != (request = requests_head))
658
660 GNUNET_free (api);
662 "PABC REST plugin is finished\n");
663 return NULL;
664}
665
666
667/* end of plugin_rest_reclaim.c */
struct GNUNET_MQ_MessageHandlers handlers[]
Definition: 003.c:1
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_FS_Handle * ctx
static char * value
Value of the record to add/remove.
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:39
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:40
static struct GNUNET_VPN_Handle * handle
Handle to vpn service.
Definition: gnunet-vpn.c:35
Identity attribute definitions.
reclaim service; implements identity and personal data sharing for GNUnet
API for helper library to parse/create REST.
GNUnet service REST plugin header.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:64
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
#define GNUNET_REST_HANDLER_END
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:44
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1305
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1278
size_t GNUNET_STRINGS_base64url_decode(const char *data, size_t len, void **out)
Decode from Base64url.
Definition: strings.c:1782
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
@ MHD_HTTP_BAD_REQUEST
Bad Request [RFC7231, Section 6.5.1].
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
enum GNUNET_GenericReturnValue PABC_write_public_parameters(char const *const pp_name, struct pabc_public_parameters *const pp)
Definition: pabc_helper.c:173
enum GNUNET_GenericReturnValue PABC_write_usr_ctx(char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context *const usr_ctx)
Definition: pabc_helper.c:227
enum GNUNET_GenericReturnValue PABC_read_usr_ctx(char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context **usr_ctx)
Definition: pabc_helper.c:301
void * libgnunet_plugin_rest_reclaim_done(void *cls)
Exit point from the plugin.
Definition: pabc_plugin.c:649
#define GNUNET_REST_API_NS_PABC
REST root namespace.
Definition: pabc_plugin.c:41
#define GNUNET_REST_API_NS_PABC_CR
Credential request endpoint.
Definition: pabc_plugin.c:46
static void do_timeout(void *cls)
Task run on timeout, sends error message.
Definition: pabc_plugin.c:192
static void return_response(void *cls)
Definition: pabc_plugin.c:202
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration handle.
Definition: pabc_plugin.c:51
static void cr_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Definition: pabc_plugin.c:308
static struct RequestHandle * requests_head
DLL.
Definition: pabc_plugin.c:128
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Respond to OPTIONS request.
Definition: pabc_plugin.c:556
static enum GNUNET_GenericReturnValue setup_new_user_context(struct pabc_context *ctx, struct pabc_public_parameters *pp, struct pabc_user_context **usr_ctx)
Definition: pabc_plugin.c:291
static char * allow_methods
HTTP methods allows for this plugin.
Definition: pabc_plugin.c:56
void * libgnunet_plugin_rest_pabc_init(void *cls)
Entry point for the plugin.
Definition: pabc_plugin.c:618
static struct RequestHandle * requests_tail
DLL.
Definition: pabc_plugin.c:133
static enum pabc_status set_attributes_from_idtoken(const struct pabc_context *ctx, const struct pabc_public_parameters *pp, struct pabc_user_context *usr_ctx, const char *id_token)
Definition: pabc_plugin.c:219
static enum GNUNET_GenericReturnValue rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Definition: pabc_plugin.c:573
static void do_error(void *cls)
Task run on error, sends error message.
Definition: pabc_plugin.c:167
static void cleanup_handle(void *cls)
Cleanup lookup handle.
Definition: pabc_plugin.c:141
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
void * cls
Closure for all of the callbacks.
struct returned by the initialization function of the plugin
char * name
Plugin name.
void * cls
The closure of the plugin.
const char * url
The url as string.
void(* proc)(struct GNUNET_REST_RequestHandle *handle, const char *url, void *cls)
Namespace to handle.
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for relative time used by GNUnet, in microseconds.
Handle for a plugin.
Definition: block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
The request handle.
Definition: config_plugin.c:46
char * emsg
Error response message.
Definition: gns_plugin.c:142
struct RequestHandle * prev
DLL.
Definition: config_plugin.c:55
int response_code
HTTP response code.
Definition: config_plugin.c:75
struct GNUNET_SCHEDULER_Task * timeout_task
ID of a task associated with the resolution process.
Definition: gns_plugin.c:122
void * proc_cls
The closure of the result processor.
Definition: config_plugin.c:70
GNUNET_REST_ResultProcessor proc
The plugin result processor.
Definition: config_plugin.c:65
struct RequestHandle * next
DLL.
Definition: config_plugin.c:50
json_t * resp_object
Response object.
struct GNUNET_REST_RequestHandle * rest_handle
Handle to rest request.
Definition: config_plugin.c:60
char * url
The URL.
Definition: config_plugin.c:80
struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gns_plugin.c:117