87238498a5e4037d1045a81efa8e1ddbb8825aa6
[oweals/gnunet.git] / src / gns / plugin_gnsrecord_gns.c
1 /*
2      This file is part of GNUnet
3      (C) 2013 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
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_dnsparser_lib.h"
34 #include "gnunet_gnsrecord_plugin.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_PSEU:
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       size_t off;
68
69       off = 0;
70       ns = GNUNET_DNSPARSER_parse_name (data,
71                                         data_size,
72                                         &off);
73       if ( (NULL == ns) ||
74            (off != data_size) )
75       {
76         GNUNET_break_op (0);
77         GNUNET_free_non_null (ns);
78         return NULL;
79       }
80       return ns;
81     }
82   case GNUNET_GNSRECORD_TYPE_VPN:
83     {
84       const struct GNUNET_TUN_GnsVpnRecord *vpn;
85       char* vpn_str;
86
87       cdata = data;
88       if ( (data_size <= sizeof (struct GNUNET_TUN_GnsVpnRecord)) ||
89            ('\0' != cdata[data_size - 1]) )
90         return NULL; /* malformed */
91       vpn = data;
92       if (0 == GNUNET_asprintf (&vpn_str, "%u %s %s",
93                                 (unsigned int) ntohs (vpn->proto),
94                                 (const char*) GNUNET_i2s_full (&vpn->peer),
95                                 (const char*) &vpn[1]))
96       {
97         GNUNET_free (vpn_str);
98         return NULL;
99       }
100       return vpn_str;
101     }
102   default:
103     return NULL;
104   }
105 }
106
107
108 /**
109  * Convert human-readable version of a 'value' of a record to the binary
110  * representation.
111  *
112  * @param cls closure, unused
113  * @param type type of the record
114  * @param s human-readable string
115  * @param data set to value in binary encoding (will be allocated)
116  * @param data_size set to number of bytes in @a data
117  * @return #GNUNET_OK on success
118  */
119 static int
120 gns_string_to_value (void *cls,
121                      uint32_t type,
122                      const char *s,
123                      void **data,
124                      size_t *data_size)
125 {
126   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
127   struct GNUNET_TUN_GnsVpnRecord *vpn;
128   char s_peer[103 + 1];
129   char s_serv[253 + 1];
130   unsigned int proto;
131
132   if (NULL == s)
133     return GNUNET_SYSERR;
134   switch (type)
135   {
136
137   case GNUNET_GNSRECORD_TYPE_PKEY:
138     if (GNUNET_OK !=
139         GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
140     {
141       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
142            _("Unable to parse PKEY record `%s'\n"),
143            s);
144       return GNUNET_SYSERR;
145     }
146     *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
147     memcpy (*data, &pkey, sizeof (pkey));
148     *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
149     return GNUNET_OK;
150
151   case GNUNET_GNSRECORD_TYPE_PSEU:
152     *data = GNUNET_strdup (s);
153     *data_size = strlen (s);
154     return GNUNET_OK;
155   case GNUNET_GNSRECORD_TYPE_LEHO:
156     *data = GNUNET_strdup (s);
157     *data_size = strlen (s);
158     return GNUNET_OK;
159   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
160     {
161       char nsbuf[256];
162       size_t off;
163
164       off = 0;
165       if (GNUNET_OK !=
166           GNUNET_DNSPARSER_builder_add_name (nsbuf,
167                                              sizeof (nsbuf),
168                                              &off,
169                                              s))
170       {
171         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
172              _("Failed to serialize GNS2DNS record with value `%s'\n"),
173              s);
174         return GNUNET_SYSERR;
175       }
176       *data_size = off;
177       *data = GNUNET_malloc (off);
178       memcpy (*data, nsbuf, off);
179       return GNUNET_OK;
180     }
181   case GNUNET_GNSRECORD_TYPE_VPN:
182     if (3 != SSCANF (s,"%u %103s %253s",
183                      &proto, s_peer, s_serv))
184     {
185       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186            _("Unable to parse VPN record string `%s'\n"),
187            s);
188       return GNUNET_SYSERR;
189     }
190     *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
191     *data = vpn = GNUNET_malloc (*data_size);
192     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
193                                                                     strlen (s_peer),
194                                                                     &vpn->peer.public_key))
195     {
196       GNUNET_free (vpn);
197       *data_size = 0;
198       return GNUNET_SYSERR;
199     }
200     vpn->proto = htons ((uint16_t) proto);
201     strcpy ((char*)&vpn[1], s_serv);
202     return GNUNET_OK;
203   default:
204     return GNUNET_SYSERR;
205   }
206 }
207
208
209 /**
210  * Mapping of record type numbers to human-readable
211  * record type names.
212  */
213 static struct {
214   const char *name;
215   uint32_t number;
216 } name_map[] = {
217   { "PKEY",  GNUNET_GNSRECORD_TYPE_PKEY },
218   { "PSEU",  GNUNET_GNSRECORD_TYPE_PSEU },
219   { "LEHO",  GNUNET_GNSRECORD_TYPE_LEHO },
220   { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
221   { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
222   { NULL, UINT32_MAX }
223 };
224
225
226 /**
227  * Convert a type name (i.e. "AAAA") to the corresponding number.
228  *
229  * @param cls closure, unused
230  * @param gns_typename name to convert
231  * @return corresponding number, UINT32_MAX on error
232  */
233 static uint32_t
234 gns_typename_to_number (void *cls,
235                         const char *gns_typename)
236 {
237   unsigned int i;
238
239   i=0;
240   while ( (name_map[i].name != NULL) &&
241           (0 != strcasecmp (gns_typename, name_map[i].name)) )
242     i++;
243   return name_map[i].number;
244 }
245
246
247 /**
248  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
249  *
250  * @param cls closure, unused
251  * @param type number of a type to convert
252  * @return corresponding typestring, NULL on error
253  */
254 static const char *
255 gns_number_to_typename (void *cls,
256                         uint32_t type)
257 {
258   unsigned int i;
259
260   i=0;
261   while ( (name_map[i].name != NULL) &&
262           (type != name_map[i].number) )
263     i++;
264   return name_map[i].name;
265 }
266
267
268 /**
269  * Entry point for the plugin.
270  *
271  * @param cls NULL
272  * @return the exported block API
273  */
274 void *
275 libgnunet_plugin_gnsrecord_gns_init (void *cls)
276 {
277   struct GNUNET_GNSRECORD_PluginFunctions *api;
278
279   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
280   api->value_to_string = &gns_value_to_string;
281   api->string_to_value = &gns_string_to_value;
282   api->typename_to_number = &gns_typename_to_number;
283   api->number_to_typename = &gns_number_to_typename;
284   return api;
285 }
286
287
288 /**
289  * Exit point from the plugin.
290  *
291  * @param cls the return value from #libgnunet_plugin_block_test_init
292  * @return NULL
293  */
294 void *
295 libgnunet_plugin_gnsrecord_gns_done (void *cls)
296 {
297   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
298
299   GNUNET_free (api);
300   return NULL;
301 }
302
303 /* end of plugin_gnsrecord_gns.c */