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