REST: nothing triggers rest
[oweals/gnunet.git] / src / gns / plugin_gnsrecord_gns.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2013, 2014, 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      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21 /**
22  * @file gns/plugin_gnsrecord_gns.c
23  * @brief gnsrecord plugin to provide the API for fundamental GNS records
24  *                  This includes the VPN record because GNS resolution
25  *                  is expected to understand VPN records and (if needed)
26  *                  map the result to A/AAAA.
27  * @author Christian Grothoff
28  */
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_dnsparser_lib.h"
33 #include "gnunet_gnsrecord_plugin.h"
34 #include <inttypes.h>
35
36
37 /**
38  * Convert the 'value' of a record to a string.
39  *
40  * @param cls closure, unused
41  * @param type type of the record
42  * @param data value in binary encoding
43  * @param data_size number of bytes in @a data
44  * @return NULL on error, otherwise human-readable representation of the value
45  */
46 static char *
47 gns_value_to_string (void *cls,
48                      uint32_t type,
49                      const void *data,
50                      size_t data_size)
51 {
52   const char *cdata;
53
54   switch (type)
55   {
56   case GNUNET_GNSRECORD_TYPE_PKEY:
57     if (data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
58       return NULL;
59     return GNUNET_CRYPTO_ecdsa_public_key_to_string (data);
60   case GNUNET_GNSRECORD_TYPE_NICK:
61     return GNUNET_strndup (data, data_size);
62   case GNUNET_GNSRECORD_TYPE_LEHO:
63     return GNUNET_strndup (data, data_size);
64   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
65     {
66       char *ns;
67       char *ip;
68       size_t off;
69       char *nstr;
70
71       off = 0;
72       ns = GNUNET_DNSPARSER_parse_name (data,
73                                         data_size,
74                                         &off);
75       ip = GNUNET_DNSPARSER_parse_name (data,
76                                         data_size,
77                                         &off);
78       if ( (NULL == ns) ||
79            (NULL == ip) ||
80            (off != data_size) )
81       {
82         GNUNET_break_op (0);
83         GNUNET_free_non_null (ns);
84         GNUNET_free_non_null (ip);
85         return NULL;
86       }
87       GNUNET_asprintf (&nstr,
88                        "%s@%s",
89                        ns,
90                        ip);
91       GNUNET_free_non_null (ns);
92       GNUNET_free_non_null (ip);
93       return nstr;
94     }
95   case GNUNET_GNSRECORD_TYPE_VPN:
96     {
97       struct GNUNET_TUN_GnsVpnRecord vpn;
98       char* vpn_str;
99
100       cdata = data;
101       if ( (data_size <= sizeof (vpn)) ||
102            ('\0' != cdata[data_size - 1]) )
103         return NULL; /* malformed */
104       /* need to memcpy for alignment */
105       GNUNET_memcpy (&vpn,
106                      data,
107                      sizeof (vpn));
108       GNUNET_asprintf (&vpn_str,
109                        "%u %s %s",
110                        (unsigned int) ntohs (vpn.proto),
111                        (const char*) GNUNET_i2s_full (&vpn.peer),
112                        (const char*) &cdata[sizeof (vpn)]);
113       return vpn_str;
114     }
115   case GNUNET_GNSRECORD_TYPE_BOX:
116     {
117       struct GNUNET_GNSRECORD_BoxRecord box;
118       uint32_t rt;
119       char *box_str;
120       char *ival;
121
122       cdata = data;
123       if (data_size < sizeof (struct GNUNET_GNSRECORD_BoxRecord))
124         return NULL; /* malformed */
125       GNUNET_memcpy (&box,
126                      data,
127                      sizeof (box));
128       rt = ntohl (box.record_type);
129       ival = GNUNET_GNSRECORD_value_to_string (rt,
130                                                &cdata[sizeof (box)],
131                                                data_size - sizeof (box));
132       if (NULL == ival)
133         return NULL; /* malformed */
134       GNUNET_asprintf (&box_str,
135                        "%u %u %u %s",
136                        (unsigned int) ntohs (box.protocol),
137                        (unsigned int) ntohs (box.service),
138                        (unsigned int) rt,
139                        ival);
140       GNUNET_free (ival);
141       return box_str;
142     }
143   default:
144     return NULL;
145   }
146 }
147
148
149 /**
150  * Convert human-readable version of a 'value' of a record to the binary
151  * representation.
152  *
153  * @param cls closure, unused
154  * @param type type of the record
155  * @param s human-readable string
156  * @param data set to value in binary encoding (will be allocated)
157  * @param data_size set to number of bytes in @a data
158  * @return #GNUNET_OK on success
159  */
160 static int
161 gns_string_to_value (void *cls,
162                      uint32_t type,
163                      const char *s,
164                      void **data,
165                      size_t *data_size)
166 {
167   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
168
169   if (NULL == s)
170     return GNUNET_SYSERR;
171   switch (type)
172   {
173
174     case GNUNET_GNSRECORD_TYPE_PKEY:
175       if (GNUNET_OK !=
176           GNUNET_CRYPTO_ecdsa_public_key_from_string (s,
177                                                       strlen (s),
178                                                       &pkey))
179       {
180         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
181                     _("Unable to parse PKEY record `%s'\n"),
182                     s);
183         return GNUNET_SYSERR;
184       }
185       *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
186       GNUNET_memcpy (*data,
187                      &pkey,
188                      sizeof (pkey));
189       *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
190       return GNUNET_OK;
191
192     case GNUNET_GNSRECORD_TYPE_NICK:
193       *data = GNUNET_strdup (s);
194       *data_size = strlen (s);
195       return GNUNET_OK;
196     case GNUNET_GNSRECORD_TYPE_LEHO:
197       *data = GNUNET_strdup (s);
198       *data_size = strlen (s);
199       return GNUNET_OK;
200     case GNUNET_GNSRECORD_TYPE_GNS2DNS:
201       {
202         char nsbuf[514];
203         char *cpy;
204         char *at;
205         size_t off;
206
207         cpy = GNUNET_strdup (s);
208         at = strchr (cpy, '@');
209         if (NULL == at)
210         {
211           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
212                       _("Unable to parse GNS2DNS record `%s'\n"),
213                       s);
214           GNUNET_free (cpy);
215           return GNUNET_SYSERR;
216         }
217         *at = '\0';
218         at++;
219
220         off = 0;
221         if ( (GNUNET_OK !=
222               GNUNET_DNSPARSER_builder_add_name (nsbuf,
223                                                  sizeof (nsbuf),
224                                                  &off,
225                                                  cpy)) ||
226              (GNUNET_OK !=
227               GNUNET_DNSPARSER_builder_add_name (nsbuf,
228                                                  sizeof (nsbuf),
229                                                  &off,
230                                                  at)) )
231         {
232           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
233                       _("Failed to serialize GNS2DNS record with value `%s'\n"),
234                       s);
235           GNUNET_free (cpy);
236           return GNUNET_SYSERR;
237         }
238         GNUNET_free (cpy);
239         *data_size = off;
240         *data = GNUNET_malloc (off);
241         GNUNET_memcpy (*data,
242                        nsbuf,
243                        off);
244         return GNUNET_OK;
245       }
246     case GNUNET_GNSRECORD_TYPE_VPN:
247       {
248         struct GNUNET_TUN_GnsVpnRecord *vpn;
249         char s_peer[103 + 1];
250         char s_serv[253 + 1];
251         unsigned int proto;
252
253         if (3 != SSCANF (s,
254                          "%u %103s %253s",
255                          &proto, s_peer, s_serv))
256         {
257           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
258                       _("Unable to parse VPN record string `%s'\n"),
259                       s);
260           return GNUNET_SYSERR;
261         }
262         *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
263         *data = vpn = GNUNET_malloc (*data_size);
264         if (GNUNET_OK !=
265             GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
266                                                         strlen (s_peer),
267                                                         &vpn->peer.public_key))
268         {
269           GNUNET_free (vpn);
270           *data_size = 0;
271           return GNUNET_SYSERR;
272         }
273         vpn->proto = htons ((uint16_t) proto);
274         strcpy ((char*)&vpn[1], s_serv);
275         return GNUNET_OK;
276       }
277     case GNUNET_GNSRECORD_TYPE_BOX:
278       {
279         struct GNUNET_GNSRECORD_BoxRecord *box;
280         size_t rest;
281         unsigned int protocol;
282         unsigned int service;
283         unsigned int record_type;
284         void *bval;
285         size_t bval_size;
286
287         if (3 != SSCANF (s,
288                          "%u %u %u ",
289                          &protocol,
290                          &service,
291                          &record_type))
292         {
293           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294                       _("Unable to parse BOX record string `%s'\n"),
295                       s);
296           return GNUNET_SYSERR;
297         }
298         rest = snprintf (NULL, 0,
299                          "%u %u %u ",
300                          protocol,
301                          service,
302                          record_type);
303         if (GNUNET_OK !=
304             GNUNET_GNSRECORD_string_to_value (record_type,
305                                               &s[rest],
306                                               &bval,
307                                               &bval_size))
308           return GNUNET_SYSERR;
309         *data_size = sizeof (struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
310         *data = box = GNUNET_malloc (*data_size);
311         box->protocol = htons (protocol);
312         box->service = htons (service);
313         box->record_type = htonl (record_type);
314         GNUNET_memcpy (&box[1],
315                        bval,
316                        bval_size);
317         GNUNET_free (bval);
318         return GNUNET_OK;
319       }
320     default:
321       return GNUNET_SYSERR;
322   }
323 }
324
325
326 /**
327  * Mapping of record type numbers to human-readable
328  * record type names.
329  */
330 static struct {
331   const char *name;
332   uint32_t number;
333 } gns_name_map[] = {
334   { "PKEY",  GNUNET_GNSRECORD_TYPE_PKEY },
335   { "NICK",  GNUNET_GNSRECORD_TYPE_NICK },
336   { "LEHO",  GNUNET_GNSRECORD_TYPE_LEHO },
337   { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
338   { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
339   { "BOX", GNUNET_GNSRECORD_TYPE_BOX },
340   { NULL, UINT32_MAX }
341 };
342
343
344 /**
345  * Convert a type name (i.e. "AAAA") to the corresponding number.
346  *
347  * @param cls closure, unused
348  * @param gns_typename name to convert
349  * @return corresponding number, UINT32_MAX on error
350  */
351 static uint32_t
352 gns_typename_to_number (void *cls,
353                         const char *gns_typename)
354 {
355   unsigned int i;
356
357   i=0;
358   while ( (NULL != gns_name_map[i].name) &&
359           (0 != strcasecmp (gns_typename,
360                             gns_name_map[i].name)) )
361     i++;
362   return gns_name_map[i].number;
363 }
364
365
366 /**
367  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
368  *
369  * @param cls closure, unused
370  * @param type number of a type to convert
371  * @return corresponding typestring, NULL on error
372  */
373 static const char *
374 gns_number_to_typename (void *cls,
375                         uint32_t type)
376 {
377   unsigned int i;
378
379   i=0;
380   while ( (NULL != gns_name_map[i].name) &&
381           (type != gns_name_map[i].number) )
382     i++;
383   return gns_name_map[i].name;
384 }
385
386
387 /**
388  * Entry point for the plugin.
389  *
390  * @param cls NULL
391  * @return the exported block API
392  */
393 void *
394 libgnunet_plugin_gnsrecord_gns_init (void *cls)
395 {
396   struct GNUNET_GNSRECORD_PluginFunctions *api;
397
398   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
399   api->value_to_string = &gns_value_to_string;
400   api->string_to_value = &gns_string_to_value;
401   api->typename_to_number = &gns_typename_to_number;
402   api->number_to_typename = &gns_number_to_typename;
403   return api;
404 }
405
406
407 /**
408  * Exit point from the plugin.
409  *
410  * @param cls the return value from #libgnunet_plugin_block_test_init()
411  * @return NULL
412  */
413 void *
414 libgnunet_plugin_gnsrecord_gns_done (void *cls)
415 {
416   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
417
418   GNUNET_free (api);
419   return NULL;
420 }
421
422 /* end of plugin_gnsrecord_gns.c */