GNUnet  0.10.x
gnunet-service-gns.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2018 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 "gnunet_util_lib.h"
28 #include "gnunet_dns_service.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_dht_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_gns_service.h"
35 #include "gns.h"
38 #include "gnunet_protocols.h"
39 
40 
44 struct GnsClient;
45 
50 {
51 
56 
61 
65  struct GnsClient *gc;
66 
71 
75  uint32_t request_id;
76 
77 };
78 
79 
83 struct GnsClient
84 {
89 
94 
99 
104 };
105 
106 
112 {
113 
119 
125 
130 
134  char *tld;
135 
136 };
137 
138 
143 
148 
152 static int v6_enabled;
153 
157 static int v4_enabled;
158 
163 
168 
173 
174 
182 int
183 GNS_find_tld (const char *tld_str,
185 {
186  if ('\0' == *tld_str)
187  return GNUNET_NO;
188  for (struct GNS_TopLevelDomain *tld = tld_head;
189  NULL != tld;
190  tld = tld->next)
191  {
192  if (0 == strcasecmp (tld_str,
193  tld->tld))
194  {
195  *pkey = tld->pkey;
196  return GNUNET_YES;
197  }
198  }
199  if (GNUNET_OK ==
200  GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1,
201  pkey))
202  return GNUNET_YES; /* TLD string *was* the public key */
203  return GNUNET_NO;
204 }
205 
206 
214 const char *
215 GNS_get_tld (const char *name)
216 {
217  const char *tld;
218 
219  tld = strrchr (name,
220  (unsigned char) '.');
221  if (NULL == tld)
222  tld = name;
223  else
224  tld++; /* skip the '.' */
225  return tld;
226 }
227 
228 
234 static void
235 shutdown_task (void *cls)
236 {
237  struct GNS_TopLevelDomain *tld;
238 
239  (void) cls;
241  "Shutting down!\n");
244  if (NULL != statistics)
245  {
246  GNUNET_STATISTICS_destroy (statistics,
247  GNUNET_NO);
248  statistics = NULL;
249  }
250  if (NULL != namecache_handle)
251  {
252  GNUNET_NAMECACHE_disconnect (namecache_handle);
253  namecache_handle = NULL;
254  }
255  if (NULL != dht_handle)
256  {
257  GNUNET_DHT_disconnect (dht_handle);
258  dht_handle = NULL;
259  }
260  while (NULL != (tld = tld_head))
261  {
262  GNUNET_CONTAINER_DLL_remove (tld_head,
263  tld_tail,
264  tld);
265  GNUNET_free (tld->tld);
266  GNUNET_free (tld);
267  }
268 }
269 
270 
278 static void
280  struct GNUNET_SERVICE_Client *client,
281  void *app_ctx)
282 {
283  struct ClientLookupHandle *clh;
284  struct GnsClient *gc = app_ctx;
285 
286  (void) cls;
288  "Client %p disconnected\n",
289  client);
290  while (NULL != (clh = gc->clh_head))
291  {
292  if (NULL != clh->lookup)
295  gc->clh_tail,
296  clh);
297  GNUNET_free (clh);
298  }
299  GNUNET_free (gc);
300 }
301 
302 
311 static void *
312 client_connect_cb (void *cls,
314  struct GNUNET_MQ_Handle *mq)
315 {
316  struct GnsClient *gc;
317 
318  (void) cls;
320  "Client %p connected\n",
321  client);
322  gc = GNUNET_new (struct GnsClient);
323  gc->client = client;
324  gc->mq = mq;
325  return gc;
326 }
327 
328 
336 static void
338  uint32_t rd_count,
339  const struct GNUNET_GNSRECORD_Data *rd)
340 {
341  struct ClientLookupHandle *clh = cls;
342  struct GnsClient *gc = clh->gc;
343  struct GNUNET_MQ_Envelope *env;
344  struct LookupResultMessage *rmsg;
345  ssize_t len;
346 
348  "Sending LOOKUP_RESULT message with %u results\n",
349  (unsigned int) rd_count);
350  len = GNUNET_GNSRECORD_records_get_size (rd_count,
351  rd);
352  if (len < 0)
353  {
354  GNUNET_break (0);
356  return;
357  }
358  if (len > UINT16_MAX - sizeof (*rmsg))
359  {
360  GNUNET_break (0);
362  return;
363  }
364  env = GNUNET_MQ_msg_extra (rmsg,
365  len,
367  rmsg->id = clh->request_id;
368  rmsg->rd_count = htonl (rd_count);
369  GNUNET_assert (len ==
371  rd,
372  len,
373  (char*) &rmsg[1]));
375  env);
377  gc->clh_tail,
378  clh);
379  GNUNET_free (clh);
380  GNUNET_STATISTICS_update (statistics,
381  "Completed lookups", 1,
382  GNUNET_NO);
383  GNUNET_STATISTICS_update (statistics,
384  "Records resolved",
385  rd_count,
386  GNUNET_NO);
387 }
388 
389 
397 static int
398 check_lookup (void *cls,
399  const struct LookupMessage *l_msg)
400 {
401  size_t nlen;
402 
403  (void) cls;
405  nlen = ntohs (l_msg->header.size) - sizeof (struct LookupMessage);
407  {
408  GNUNET_break (0);
409  return GNUNET_SYSERR;
410  }
411  return GNUNET_OK;
412 }
413 
414 
422 static void
423 handle_lookup (void *cls,
424  const struct LookupMessage *sh_msg)
425 {
426  struct GnsClient *gc = cls;
428  struct ClientLookupHandle *clh;
429  char *nameptr = name;
430  const char *utf_in;
431 
433  utf_in = (const char *) &sh_msg[1];
435  nameptr);
437  "Received LOOKUP `%s' message\n",
438  name);
439  clh = GNUNET_new (struct ClientLookupHandle);
441  gc->clh_tail,
442  clh);
443  clh->gc = gc;
444  clh->request_id = sh_msg->id;
445  if ( (GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
446  (GNUNET_OK != v4_enabled) )
447  {
449  "LOOKUP: Query for A record but AF_INET not supported!");
451  0,
452  NULL);
453  return;
454  }
455  if ( (GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
456  (GNUNET_OK != v6_enabled) )
457  {
459  "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
461  0,
462  NULL);
463  return;
464  }
465  clh->lookup = GNS_resolver_lookup (&sh_msg->zone,
466  ntohl (sh_msg->type),
467  name,
468  (enum GNUNET_GNS_LocalOptions) ntohs (sh_msg->options),
469  &send_lookup_response, clh);
470  GNUNET_STATISTICS_update (statistics,
471  "Lookup attempts",
472  1, GNUNET_NO);
473 }
474 
475 
484 static void
485 read_service_conf (void *cls,
486  const char *section,
487  const char *option,
488  const char *value)
489 {
491  struct GNS_TopLevelDomain *tld;
492 
493  (void) cls;
494  (void) section;
495  if (option[0] != '.')
496  return;
497  if (GNUNET_OK !=
499  strlen (value),
500  &pk,
501  sizeof (pk)))
502  {
504  section,
505  option,
506  _("Properly base32-encoded public key required"));
507  return;
508  }
509  tld = GNUNET_new (struct GNS_TopLevelDomain);
510  tld->tld = GNUNET_strdup (&option[1]);
511  tld->pkey = pk;
512  GNUNET_CONTAINER_DLL_insert (tld_head,
513  tld_tail,
514  tld);
515 }
516 
517 
525 static void
526 run (void *cls,
527  const struct GNUNET_CONFIGURATION_Handle *c,
529 {
530  unsigned long long max_parallel_bg_queries = 16;
531 
533  "gns",
535  NULL);
536  v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
538  namecache_handle = GNUNET_NAMECACHE_connect (c);
539  if (NULL == namecache_handle)
540  {
542  _("Failed to connect to the namecache!\n"));
544  return;
545  }
546  if (GNUNET_OK ==
548  "gns",
549  "MAX_PARALLEL_BACKGROUND_QUERIES",
550  &max_parallel_bg_queries))
551  {
553  "Number of allowed parallel background queries: %llu\n",
554  max_parallel_bg_queries);
555  }
556  dht_handle = GNUNET_DHT_connect (c,
557  (unsigned int) max_parallel_bg_queries);
558  if (NULL == dht_handle)
559  {
561  _("Could not connect to DHT!\n"));
563  NULL);
564  return;
565  }
566  GNS_resolver_init (namecache_handle,
567  dht_handle,
568  c,
569  max_parallel_bg_queries);
570  if ( (GNUNET_YES ==
572  "gns",
573  "INTERCEPT_DNS")) &&
574  (GNUNET_SYSERR ==
575  GNS_interceptor_init (c)) )
576  {
577  GNUNET_break (0);
579  NULL);
580  return;
581  }
582  statistics = GNUNET_STATISTICS_create ("gns",
583  c);
585  NULL);
586 }
587 
588 
593 ("gns",
595  &run,
598  NULL,
601  struct LookupMessage,
602  NULL),
604 
605 
606 /* end of gnunet-service-gns.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Process GNS requests.
Message from client to GNS service to lookup records.
Definition: gns.h:36
struct GNUNET_NAMECACHE_Handle * GNUNET_NAMECACHE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the namecache service.
Message from GNS service to client: new results.
Definition: gns.h:76
uint32_t id
Unique identifier for this request (for key collisions).
Definition: gns.h:46
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
GNUNET_NETWORK_STRUCT_END ssize_t GNUNET_GNSRECORD_records_get_size(unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Calculate how many bytes we will need to serialize the given records.
struct GNS_TopLevelDomain * next
Kept in a DLL, as there are unlikely enough of these to warrant a hash map.
static struct GNUNET_CRYPTO_EddsaPrivateKey * pk
Private key of this peer.
void GNS_resolver_lookup_cancel(struct GNS_ResolverHandle *rh)
Cancel active resolution (i.e.
struct ClientLookupHandle * prev
We keep these in a DLL.
int GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
static struct GNS_TopLevelDomain * tld_head
Head of DLL of TLDs we map to GNS zones.
static char * pkey
Public key of the zone to look in, in ASCII.
uint32_t rd_count
The number of records contained in response.
Definition: gns.h:91
void GNUNET_CONFIGURATION_iterate_section_values(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over values of a section in the configuration.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNS_TopLevelDomain * prev
Kept in a DLL, as there are unlikely enough of these to warrant a hash map.
Handle to a service.
Definition: service.c:116
struct GNUNET_CRYPTO_EcdsaPublicKey zone
Zone that is to be used for lookup.
Definition: gns.h:51
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition: service.c:2734
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1293
ssize_t GNUNET_GNSRECORD_records_serialize(unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd, size_t dest_size, char *dest)
Serialize the given records to the given destination buffer.
const char * GNS_get_tld(const char *name)
Obtain the TLD of the given name.
#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP
Client would like to resolve a name.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
Called whenever a client is disconnected.
struct GNUNET_CRYPTO_EcdsaPublicKey pkey
Public key associated with the tld.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
int GNUNET_GNSRECORD_zkey_to_pkey(const char *zkey, struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
Convert an absolute domain name to the respective public key.
#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT
Service response to name resolution request from client.
GNUNET_GNS_LocalOptions
Options for the GNS lookup.
struct ClientLookupHandle * next
We keep these in a DLL.
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
int32_t type
the type of record to look up
Definition: gns.h:67
#define GNUNET_new(type)
Allocate a struct or union of the given type.
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:524
Handle for the service.
static int v6_enabled
GNUNET_YES if ipv6 is supported
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
IPC messages between GNS API and GNS service.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int GNS_interceptor_init(const struct GNUNET_CONFIGURATION_Handle *c)
Initialized the interceptor.
Handle to a currenty pending resolution.
Connection to the DHT service.
Definition: dht_api.c:205
struct GNUNET_MQ_Handle * mq
The MQ.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static char * section
Name of the section.
Definition: gnunet-config.c:33
static struct GNUNET_STATISTICS_Handle * statistics
Handle to the statistics service.
Handle to a client that is connected to a service.
Definition: service.c:249
static int check_lookup(void *cls, const struct LookupMessage *l_msg)
Checks a GNUNET_MESSAGE_TYPE_GNS_LOOKUP message.
struct GNUNET_SERVICE_Client * client
The client.
uint32_t request_id
request id
struct GNUNET_MessageHeader header
Header of type GNUNET_MESSAGE_TYPE_GNS_LOOKUP.
Definition: gns.h:41
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct...
Definition: gnunet_mq_lib.h:52
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH
Maximum length of a name in DNS.
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
static void shutdown_task(void *cls)
Task run during shutdown.
static char * value
Value of the record to add/remove.
uint32_t id
Unique identifier for this request (for key collisions).
Definition: gns.h:86
static struct GNUNET_DHT_Handle * dht_handle
Our handle to the DHT.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
static void handle_lookup(void *cls, const struct LookupMessage *sh_msg)
Handle lookup requests from client.
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:1273
static struct GNUNET_NAMECACHE_Handle * namecache_handle
Our handle to the namecache service.
static struct GNS_TopLevelDomain * tld_tail
Tail of DLL of TLDs we map to GNS zones.
static char * option
Name of the option.
Definition: gnunet-config.c:38
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
Add a client to our list of active clients.
void GNS_interceptor_done()
Disconnect from interceptor.
struct GnsClient * gc
Client handle.
void GNS_resolver_done()
Shutdown resolver.
static int v4_enabled
GNUNET_YES if ipv4 is supported
struct GNS_ResolverHandle * lookup
Active handle for the lookup.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2618
Handle to a lookup operation from client via API.
int16_t options
Local options for where to look for results (an enum GNUNET_GNS_LocalOptions in NBO).
Definition: gns.h:57
GNUnet GNS service.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
struct GNUNET_DHT_Handle * GNUNET_DHT_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int ht_len)
Initialize the connection with the DHT service.
Definition: dht_api.c:895
const char * name
void GNUNET_DHT_disconnect(struct GNUNET_DHT_Handle *handle)
Shutdown connection with the DHT service.
Definition: dht_api.c:923
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
struct GNS_ResolverHandle * GNS_resolver_lookup(const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t record_type, const char *name, enum GNUNET_GNS_LocalOptions options, GNS_ResultProcessor proc, void *proc_cls)
Lookup of a record in a specific zone calls lookup result processor on result.
void GNS_resolver_init(struct GNUNET_NAMECACHE_Handle *nc, struct GNUNET_DHT_Handle *dht, const struct GNUNET_CONFIGURATION_Handle *c, unsigned long long max_bg_queries)
Initialize the resolver.
static void read_service_conf(void *cls, const char *section, const char *option, const char *value)
Reads the configuration and populates TLDs.
Handle to a message queue.
Definition: mq.c:85
Information we track per connected client.
#define GNUNET_DNSPARSER_TYPE_AAAA
configuration data
Definition: configuration.c:85
Representation of a TLD, mapping the respective TLD string (i.e.
int GNS_find_tld(const char *tld_str, struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
Find GNS zone belonging to TLD tld.
struct ClientLookupHandle * clh_head
Head of the DLL.
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
Connection to the NAMECACHE service.
Definition: namecache_api.c:96
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
static void send_lookup_response(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Reply to client with the result from our lookup.
char * tld
Top-level domain as a string, including leading ".".
void GNUNET_NAMECACHE_disconnect(struct GNUNET_NAMECACHE_Handle *h)
Disconnect from the namecache service (and free associated resources).
#define GNUNET_YES
Definition: gnunet_common.h:80
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:353
GNUNET_SERVICE_MAIN("gns", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_var_size(lookup, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, struct LookupMessage, NULL), GNUNET_MQ_handler_end())
Define "main" method using service macro.
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
#define GNUNET_DNSPARSER_TYPE_A
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2533
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
int GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:1021
int GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition: network.c:84
struct ClientLookupHandle * clh_tail
Tail of the DLL.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_STRINGS_utf8_tolower(const char *input, char *output)
Convert the utf-8 input string to lower case.
Definition: strings.c:558
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...