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