fix possible buffer overrun
[oweals/gnunet.git] / src / namecache / namecache_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2013, 2016 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
19 /**
20  * @file namecache/namecache_api.c
21  * @brief API to access the NAMECACHE service
22  * @author Martin Schanzenbach
23  * @author Matthias Wachs
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_dnsparser_lib.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_signatures.h"
34 #include "gnunet_namecache_service.h"
35 #include "namecache.h"
36
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
39
40
41 /**
42  * An QueueEntry used to store information for a pending
43  * NAMECACHE record operation
44  */
45 struct GNUNET_NAMECACHE_QueueEntry
46 {
47
48   /**
49    * Kept in a DLL.
50    */
51   struct GNUNET_NAMECACHE_QueueEntry *next;
52
53   /**
54    * Kept in a DLL.
55    */
56   struct GNUNET_NAMECACHE_QueueEntry *prev;
57
58   /**
59    * Main handle to access the namecache.
60    */
61   struct GNUNET_NAMECACHE_Handle *nsh;
62
63   /**
64    * Continuation to call
65    */
66   GNUNET_NAMECACHE_ContinuationWithStatus cont;
67
68   /**
69    * Closure for @e cont.
70    */
71   void *cont_cls;
72
73   /**
74    * Function to call with the blocks we get back; or NULL.
75    */
76   GNUNET_NAMECACHE_BlockProcessor block_proc;
77
78   /**
79    * Closure for @e block_proc.
80    */
81   void *block_proc_cls;
82
83   /**
84    * The operation id this zone iteration operation has
85    */
86   uint32_t op_id;
87
88 };
89
90
91 /**
92  * Connection to the NAMECACHE service.
93  */
94 struct GNUNET_NAMECACHE_Handle
95 {
96
97   /**
98    * Configuration to use.
99    */
100   const struct GNUNET_CONFIGURATION_Handle *cfg;
101
102   /**
103    * Message queue to service.
104    */
105   struct GNUNET_MQ_Handle *mq;
106
107   /**
108    * Currently pending transmission request (or NULL).
109    */
110   struct GNUNET_CLIENT_TransmitHandle *th;
111
112   /**
113    * Head of pending namecache queue entries
114    */
115   struct GNUNET_NAMECACHE_QueueEntry *op_head;
116
117   /**
118    * Tail of pending namecache queue entries
119    */
120   struct GNUNET_NAMECACHE_QueueEntry *op_tail;
121
122   /**
123    * Reconnect task
124    */
125   struct GNUNET_SCHEDULER_Task *reconnect_task;
126
127   /**
128    * Delay introduced before we reconnect.
129    */
130   struct GNUNET_TIME_Relative reconnect_delay;
131
132   /**
133    * Should we reconnect to service due to some serious error?
134    */
135   int reconnect;
136
137   /**
138    * The last operation id used for a NAMECACHE operation
139    */
140   uint32_t last_op_id_used;
141
142 };
143
144
145 /**
146  * Disconnect from service and then reconnect.
147  *
148  * @param h our handle
149  */
150 static void
151 force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
152
153
154 /**
155  * Find queue entry for the given @a rid.
156  *
157  * @param h handle to search
158  * @param rid request ID to look for
159  * @return NULL if not found, otherwise the queue entry (removed from the queue)
160  */
161 static struct GNUNET_NAMECACHE_QueueEntry *
162 find_qe (struct GNUNET_NAMECACHE_Handle *h,
163          uint32_t rid)
164 {
165   struct GNUNET_NAMECACHE_QueueEntry *qe;
166
167   for (qe = h->op_head; qe != NULL; qe = qe->next)
168   {
169     if (qe->op_id == rid)
170     {
171       GNUNET_CONTAINER_DLL_remove (h->op_head,
172                                    h->op_tail,
173                                    qe);
174       return qe;
175     }
176   }
177   return NULL;
178 }
179
180
181 /**
182  * Handle an incoming message of type
183  * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
184  *
185  * @param cls the `struct GNUNET_NAMECACHE_Handle`
186  * @param msg the message we received
187  */
188 static int
189 check_lookup_block_response (void *cls,
190                              const struct LookupBlockResponseMessage *msg)
191 {
192   /* any length will do, format validation is in handler */
193   return GNUNET_OK;
194 }
195
196
197 /**
198  * Handle an incoming message of type
199  * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
200  *
201  * @param cls the `struct GNUNET_NAMECACHE_Handle`
202  * @param msg the message we received
203  */
204 static void
205 handle_lookup_block_response (void *cls,
206                               const struct LookupBlockResponseMessage *msg)
207 {
208   struct GNUNET_NAMECACHE_Handle *h = cls;
209   size_t size;
210   struct GNUNET_NAMECACHE_QueueEntry *qe;
211
212   LOG (GNUNET_ERROR_TYPE_DEBUG,
213        "Received LOOKUP_BLOCK_RESPONSE\n");
214   qe = find_qe (h,
215                 ntohl (msg->gns_header.r_id));
216   if (NULL == qe)
217     return;
218   if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
219   {
220     /* no match found */
221     if (NULL != qe->block_proc)
222       qe->block_proc (qe->block_proc_cls,
223                       NULL);
224     GNUNET_free (qe);
225     return;
226   }
227   if (ntohs (msg->gns_header.header.size) < sizeof (struct LookupBlockResponseMessage))
228   {
229     LOG (GNUNET_ERROR_TYPE_ERROR,
230          "Message is too short\n");
231     return;
232   }
233   size = ntohs (msg->gns_header.header.size)
234     - sizeof (struct LookupBlockResponseMessage);
235   {
236     char buf[size + sizeof (struct GNUNET_GNSRECORD_Block)] GNUNET_ALIGN;
237     struct GNUNET_GNSRECORD_Block *block;
238
239     block = (struct GNUNET_GNSRECORD_Block *) buf;
240     block->signature = msg->signature;
241     block->derived_key = msg->derived_key;
242     block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
243     block->purpose.size = htonl (size +
244                                  sizeof (struct GNUNET_TIME_AbsoluteNBO) +
245                                  sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
246     block->expiration_time = msg->expire;
247     GNUNET_memcpy (&block[1],
248             &msg[1],
249             size);
250     if (GNUNET_OK !=
251         GNUNET_GNSRECORD_block_verify (block))
252     {
253       GNUNET_break (0);
254       if (NULL != qe->block_proc)
255         qe->block_proc (qe->block_proc_cls,
256                         NULL);
257       force_reconnect (h);
258     }
259     else
260     {
261       if (NULL != qe->block_proc)
262         qe->block_proc (qe->block_proc_cls,
263                         block);
264     }
265   }
266   GNUNET_free (qe);
267 }
268
269
270 /**
271  * Handle an incoming message of type
272  * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
273  *
274  * @param cls the `struct GNUNET_NAMECACHE_Handle`
275  * @param msg the message we received
276  * @param size the message size
277  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
278  */
279 static void
280 handle_block_cache_response (void *cls,
281                              const struct BlockCacheResponseMessage *msg)
282 {
283   struct GNUNET_NAMECACHE_Handle *h = cls;
284   struct GNUNET_NAMECACHE_QueueEntry *qe;
285   int res;
286
287   LOG (GNUNET_ERROR_TYPE_DEBUG,
288        "Received BLOCK_CACHE_RESPONSE\n");
289   qe = find_qe (h,
290                 ntohl (msg->gns_header.r_id));
291   if (NULL == qe)
292     return;
293   res = ntohl (msg->op_result);
294   /* TODO: add actual error message from namecache to response... */
295   if (NULL != qe->cont)
296     qe->cont (qe->cont_cls,
297               res,
298               (GNUNET_OK == res)
299               ? NULL
300               : _("Namecache failed to cache block"));
301   GNUNET_free (qe);
302 }
303
304
305 /**
306  * Generic error handler, called with the appropriate error code and
307  * the same closure specified at the creation of the message queue.
308  * Not every message queue implementation supports an error handler.
309  *
310  * @param cls closure with the `struct GNUNET_NAMECACHE_Handle *`
311  * @param error error code
312  */
313 static void
314 mq_error_handler (void *cls,
315                   enum GNUNET_MQ_Error error)
316 {
317   struct GNUNET_NAMECACHE_Handle *h = cls;
318
319   force_reconnect (h);
320 }
321
322
323 /**
324  * Reconnect to namecache service.
325  *
326  * @param h the handle to the NAMECACHE service
327  */
328 static void
329 reconnect (struct GNUNET_NAMECACHE_Handle *h)
330 {
331   struct GNUNET_MQ_MessageHandler handlers[] = {
332     GNUNET_MQ_hd_var_size (lookup_block_response,
333                            GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE,
334                            struct LookupBlockResponseMessage,
335                            h),
336     GNUNET_MQ_hd_fixed_size (block_cache_response,
337                              GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE,
338                              struct BlockCacheResponseMessage,
339                              h),
340     GNUNET_MQ_handler_end ()
341   };
342   GNUNET_assert (NULL == h->mq);
343   h->mq = GNUNET_CLIENT_connect (h->cfg,
344                                  "namecache",
345                                  handlers,
346                                  &mq_error_handler,
347                                  h);
348 }
349
350
351 /**
352  * Re-establish the connection to the service.
353  *
354  * @param cls handle to use to re-connect.
355  */
356 static void
357 reconnect_task (void *cls)
358 {
359   struct GNUNET_NAMECACHE_Handle *h = cls;
360
361   h->reconnect_task = NULL;
362   reconnect (h);
363 }
364
365
366 /**
367  * Disconnect from service and then reconnect.
368  *
369  * @param h our handle
370  */
371 static void
372 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
373 {
374   struct GNUNET_NAMECACHE_QueueEntry *qe;
375
376   h->reconnect = GNUNET_NO;
377   GNUNET_MQ_destroy (h->mq);
378   h->mq = NULL;
379   while (NULL != (qe = h->op_head))
380   {
381     GNUNET_CONTAINER_DLL_remove (h->op_head,
382                                  h->op_tail,
383                                  qe);
384     if (NULL != qe->cont)
385       qe->cont (qe->cont_cls,
386                 GNUNET_SYSERR,
387                 _("Error communicating with namecache service"));
388     GNUNET_free (qe);
389   }
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391               "Reconnecting to namecache\n");
392   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
393   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
394                                                     &reconnect_task,
395                                                     h);
396 }
397
398
399 /**
400  * Get a fresh operation id to distinguish between namecache requests
401  *
402  * @param h the namecache handle
403  * @return next operation id to use
404  */
405 static uint32_t
406 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
407 {
408   return h->last_op_id_used++;
409 }
410
411
412 /**
413  * Initialize the connection with the NAMECACHE service.
414  *
415  * @param cfg configuration to use
416  * @return handle to the GNS service, or NULL on error
417  */
418 struct GNUNET_NAMECACHE_Handle *
419 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
420 {
421   struct GNUNET_NAMECACHE_Handle *h;
422
423   h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
424   h->cfg = cfg;
425   reconnect (h);
426   if (NULL == h->mq)
427   {
428     GNUNET_free (h);
429     return NULL;
430   }
431   return h;
432 }
433
434
435 /**
436  * Disconnect from the namecache service (and free associated
437  * resources).
438  *
439  * @param h handle to the namecache
440  */
441 void
442 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
443 {
444   struct GNUNET_NAMECACHE_QueueEntry *q;
445
446   GNUNET_break (NULL == h->op_head);
447   while (NULL != (q = h->op_head))
448   {
449     GNUNET_CONTAINER_DLL_remove (h->op_head,
450                                  h->op_tail,
451                                  q);
452     GNUNET_free (q);
453   }
454   if (NULL != h->mq)
455   {
456     GNUNET_MQ_destroy (h->mq);
457     h->mq = NULL;
458   }
459   if (NULL != h->reconnect_task)
460   {
461     GNUNET_SCHEDULER_cancel (h->reconnect_task);
462     h->reconnect_task = NULL;
463   }
464   GNUNET_free (h);
465 }
466
467
468 /**
469  * Store an item in the namecache.  If the item is already present,
470  * it is replaced with the new record.
471  *
472  * @param h handle to the namecache
473  * @param block block to store
474  * @param cont continuation to call when done
475  * @param cont_cls closure for @a cont
476  * @return handle to abort the request, NULL on error
477  */
478 struct GNUNET_NAMECACHE_QueueEntry *
479 GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
480                               const struct GNUNET_GNSRECORD_Block *block,
481                               GNUNET_NAMECACHE_ContinuationWithStatus cont,
482                               void *cont_cls)
483 {
484   struct GNUNET_NAMECACHE_QueueEntry *qe;
485   struct BlockCacheMessage *msg;
486   struct GNUNET_MQ_Envelope *env;
487   uint32_t rid;
488   size_t blen;
489
490   if (NULL == h->mq)
491     return NULL;
492   blen = ntohl (block->purpose.size)
493     - sizeof (struct GNUNET_TIME_AbsoluteNBO)
494     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
495   rid = get_op_id (h);
496   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
497   qe->nsh = h;
498   qe->cont = cont;
499   qe->cont_cls = cont_cls;
500   qe->op_id = rid;
501   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
502                                     h->op_tail,
503                                     qe);
504   /* send msg */
505   env = GNUNET_MQ_msg_extra (msg,
506                              blen,
507                              GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
508   msg->gns_header.r_id = htonl (rid);
509   msg->expire = block->expiration_time;
510   msg->signature = block->signature;
511   msg->derived_key = block->derived_key;
512   GNUNET_memcpy (&msg[1],
513           &block[1],
514           blen);
515   GNUNET_MQ_send (h->mq,
516                   env);
517   return qe;
518 }
519
520
521 /**
522  * Get a result for a particular key from the namecache.  The processor
523  * will only be called once.
524  *
525  * @param h handle to the namecache
526  * @param derived_hash hash of zone key combined with name to lookup
527  * @param proc function to call on the matching block, or with
528  *        NULL if there is no matching block
529  * @param proc_cls closure for @a proc
530  * @return a handle that can be used to cancel, NULL on error
531  */
532 struct GNUNET_NAMECACHE_QueueEntry *
533 GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
534                                const struct GNUNET_HashCode *derived_hash,
535                                GNUNET_NAMECACHE_BlockProcessor proc,
536                                void *proc_cls)
537 {
538   struct GNUNET_NAMECACHE_QueueEntry *qe;
539   struct LookupBlockMessage *msg;
540   struct GNUNET_MQ_Envelope *env;
541   uint32_t rid;
542
543   if (NULL == h->mq)
544     return NULL;
545   LOG (GNUNET_ERROR_TYPE_DEBUG,
546        "Looking for block under %s\n",
547        GNUNET_h2s (derived_hash));
548   rid = get_op_id (h);
549   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
550   qe->nsh = h;
551   qe->block_proc = proc;
552   qe->block_proc_cls = proc_cls;
553   qe->op_id = rid;
554   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
555                                     h->op_tail,
556                                     qe);
557   env = GNUNET_MQ_msg (msg,
558                        GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
559   msg->gns_header.r_id = htonl (rid);
560   msg->query = *derived_hash;
561   GNUNET_MQ_send (h->mq,
562                   env);
563   return qe;
564 }
565
566
567 /**
568  * Cancel a namecache operation.  The final callback from the
569  * operation must not have been done yet.
570  *
571  * @param qe operation to cancel
572  */
573 void
574 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
575 {
576   struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
577
578   GNUNET_CONTAINER_DLL_remove (h->op_head,
579                                h->op_tail,
580                                qe);
581   GNUNET_free(qe);
582 }
583
584
585 /* end of namecache_api.c */