diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-06-30 19:21:05 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-06-30 19:21:05 +0000 |
commit | 17de5c9d798109f55059190c886609ba377e4eb6 (patch) | |
tree | 07f2b4241f433b18baf02d5bf189307ad2308166 /src/namestore/namestore_api_common.c | |
parent | fd87b25438487e1215c68bdb9f1bcac2d7012bc2 (diff) | |
download | gnunet-17de5c9d798109f55059190c886609ba377e4eb6.tar.gz gnunet-17de5c9d798109f55059190c886609ba377e4eb6.zip |
-towards implementing improved namestore API
Diffstat (limited to 'src/namestore/namestore_api_common.c')
-rw-r--r-- | src/namestore/namestore_api_common.c | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/src/namestore/namestore_api_common.c b/src/namestore/namestore_api_common.c new file mode 100644 index 000000000..ab2506611 --- /dev/null +++ b/src/namestore/namestore_api_common.c | |||
@@ -0,0 +1,755 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010, 2012 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 namestore/namestore_common.c | ||
23 | * @brief API to access the NAMESTORE service | ||
24 | * @author Martin Schanzenbach | ||
25 | * @author Matthias Wachs | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_constants.h" | ||
31 | #include "gnunet_signatures.h" | ||
32 | #include "gnunet_arm_service.h" | ||
33 | #include "gnunet_namestore_service.h" | ||
34 | #include "gnunet_dnsparser_lib.h" | ||
35 | #include "gns_protocol.h" | ||
36 | #include "namestore.h" | ||
37 | |||
38 | |||
39 | #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) | ||
40 | |||
41 | GNUNET_NETWORK_STRUCT_BEGIN | ||
42 | |||
43 | /** | ||
44 | * Internal format of a record in the serialized form. | ||
45 | */ | ||
46 | struct NetworkRecord | ||
47 | { | ||
48 | |||
49 | /** | ||
50 | * Expiration time for the DNS record; relative or absolute depends | ||
51 | * on 'flags', network byte order. | ||
52 | */ | ||
53 | uint64_t expiration_time GNUNET_PACKED; | ||
54 | |||
55 | /** | ||
56 | * Number of bytes in 'data', network byte order. | ||
57 | */ | ||
58 | uint32_t data_size GNUNET_PACKED; | ||
59 | |||
60 | /** | ||
61 | * Type of the GNS/DNS record, network byte order. | ||
62 | */ | ||
63 | uint32_t record_type GNUNET_PACKED; | ||
64 | |||
65 | /** | ||
66 | * Flags for the record, network byte order. | ||
67 | */ | ||
68 | uint32_t flags GNUNET_PACKED; | ||
69 | |||
70 | }; | ||
71 | |||
72 | GNUNET_NETWORK_STRUCT_END | ||
73 | |||
74 | /** | ||
75 | * Convert a UTF-8 string to UTF-8 lowercase | ||
76 | * @param src source string | ||
77 | * @return converted result | ||
78 | */ | ||
79 | char * | ||
80 | GNUNET_NAMESTORE_normalize_string (const char *src) | ||
81 | { | ||
82 | GNUNET_assert (NULL != src); | ||
83 | char *res = strdup (src); | ||
84 | /* normalize */ | ||
85 | GNUNET_STRINGS_utf8_tolower(src, &res); | ||
86 | return res; | ||
87 | } | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Convert a short hash to a string (for printing debug messages). | ||
92 | * This is one of the very few calls in the entire API that is | ||
93 | * NOT reentrant! | ||
94 | * | ||
95 | * @param hc the short hash code | ||
96 | * @return string form; will be overwritten by next call to GNUNET_h2s. | ||
97 | */ | ||
98 | const char * | ||
99 | GNUNET_NAMESTORE_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc) | ||
100 | { | ||
101 | static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret; | ||
102 | |||
103 | GNUNET_CRYPTO_short_hash_to_enc (hc, &ret); | ||
104 | return (const char *) &ret; | ||
105 | } | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Calculate how many bytes we will need to serialize the given | ||
110 | * records. | ||
111 | * | ||
112 | * @param rd_count number of records in the rd array | ||
113 | * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements | ||
114 | * | ||
115 | * @return the required size to serialize | ||
116 | * | ||
117 | */ | ||
118 | size_t | ||
119 | GNUNET_NAMESTORE_records_get_size (unsigned int rd_count, | ||
120 | const struct GNUNET_NAMESTORE_RecordData *rd) | ||
121 | { | ||
122 | unsigned int i; | ||
123 | size_t ret; | ||
124 | |||
125 | ret = sizeof (struct NetworkRecord) * rd_count; | ||
126 | for (i=0;i<rd_count;i++) | ||
127 | { | ||
128 | GNUNET_assert ((ret + rd[i].data_size) >= ret); | ||
129 | ret += rd[i].data_size; | ||
130 | } | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | |||
135 | /** | ||
136 | * Serialize the given records to the given destination buffer. | ||
137 | * | ||
138 | * @param rd_count number of records in the rd array | ||
139 | * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements | ||
140 | * @param dest_size size of the destination array | ||
141 | * @param dest where to write the result | ||
142 | * | ||
143 | * @return the size of serialized records, -1 if records do not fit | ||
144 | */ | ||
145 | ssize_t | ||
146 | GNUNET_NAMESTORE_records_serialize (unsigned int rd_count, | ||
147 | const struct GNUNET_NAMESTORE_RecordData *rd, | ||
148 | size_t dest_size, | ||
149 | char *dest) | ||
150 | { | ||
151 | struct NetworkRecord rec; | ||
152 | unsigned int i; | ||
153 | size_t off; | ||
154 | |||
155 | off = 0; | ||
156 | for (i=0;i<rd_count;i++) | ||
157 | { | ||
158 | rec.expiration_time = GNUNET_htonll (rd[i].expiration_time); | ||
159 | rec.data_size = htonl ((uint32_t) rd[i].data_size); | ||
160 | rec.record_type = htonl (rd[i].record_type); | ||
161 | rec.flags = htonl (rd[i].flags); | ||
162 | if (off + sizeof (rec) > dest_size) | ||
163 | return -1; | ||
164 | memcpy (&dest[off], &rec, sizeof (rec)); | ||
165 | off += sizeof (rec); | ||
166 | if (off + rd[i].data_size > dest_size) | ||
167 | return -1; | ||
168 | memcpy (&dest[off], rd[i].data, rd[i].data_size); | ||
169 | off += rd[i].data_size; | ||
170 | } | ||
171 | return off; | ||
172 | } | ||
173 | |||
174 | |||
175 | /** | ||
176 | * Compares if two records are equal (ignoring flags such | ||
177 | * as authority, private and pending, but not relative vs. | ||
178 | * absolute expiration time). | ||
179 | * | ||
180 | * @param a record | ||
181 | * @param b record | ||
182 | * @return GNUNET_YES if the records are equal or GNUNET_NO if they are not | ||
183 | */ | ||
184 | int | ||
185 | GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a, | ||
186 | const struct GNUNET_NAMESTORE_RecordData *b) | ||
187 | { | ||
188 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
189 | "Comparing records\n"); | ||
190 | if (a->record_type != b->record_type) | ||
191 | { | ||
192 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
193 | "Record type %lu != %lu\n", a->record_type, b->record_type); | ||
194 | return GNUNET_NO; | ||
195 | } | ||
196 | if ((a->expiration_time != b->expiration_time) && | ||
197 | ((a->expiration_time != 0) && (b->expiration_time != 0))) | ||
198 | { | ||
199 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
200 | "Expiration time %llu != %llu\n", a->expiration_time, b->expiration_time); | ||
201 | return GNUNET_NO; | ||
202 | } | ||
203 | if ((a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS) | ||
204 | != (b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS)) | ||
205 | { | ||
206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
207 | "Flags %lu (%lu) != %lu (%lu)\n", a->flags, | ||
208 | a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS, b->flags, | ||
209 | b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS); | ||
210 | return GNUNET_NO; | ||
211 | } | ||
212 | if (a->data_size != b->data_size) | ||
213 | { | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
215 | "Data size %lu != %lu\n", a->data_size, b->data_size); | ||
216 | return GNUNET_NO; | ||
217 | } | ||
218 | if (0 != memcmp (a->data, b->data, a->data_size)) | ||
219 | { | ||
220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
221 | "Data contents do not match\n"); | ||
222 | return GNUNET_NO; | ||
223 | } | ||
224 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
225 | "Records are equal\n"); | ||
226 | return GNUNET_YES; | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Deserialize the given records to the given destination. | ||
232 | * | ||
233 | * @param len size of the serialized record data | ||
234 | * @param src the serialized record data | ||
235 | * @param rd_count number of records in the rd array | ||
236 | * @param dest where to put the data | ||
237 | * | ||
238 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | ||
239 | */ | ||
240 | int | ||
241 | GNUNET_NAMESTORE_records_deserialize (size_t len, | ||
242 | const char *src, | ||
243 | unsigned int rd_count, | ||
244 | struct GNUNET_NAMESTORE_RecordData *dest) | ||
245 | { | ||
246 | struct NetworkRecord rec; | ||
247 | unsigned int i; | ||
248 | size_t off; | ||
249 | |||
250 | off = 0; | ||
251 | for (i=0;i<rd_count;i++) | ||
252 | { | ||
253 | if (off + sizeof (rec) > len) | ||
254 | return GNUNET_SYSERR; | ||
255 | memcpy (&rec, &src[off], sizeof (rec)); | ||
256 | dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time); | ||
257 | dest[i].data_size = ntohl ((uint32_t) rec.data_size); | ||
258 | dest[i].record_type = ntohl (rec.record_type); | ||
259 | dest[i].flags = ntohl (rec.flags); | ||
260 | off += sizeof (rec); | ||
261 | |||
262 | if (off + dest[i].data_size > len) | ||
263 | return GNUNET_SYSERR; | ||
264 | dest[i].data = &src[off]; | ||
265 | off += dest[i].data_size; | ||
266 | } | ||
267 | return GNUNET_OK; | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * Sign name and records | ||
273 | * | ||
274 | * @param key the private key | ||
275 | * @param expire block expiration | ||
276 | * @param name the name | ||
277 | * @param rd record data | ||
278 | * @param rd_count number of records | ||
279 | * | ||
280 | * @return the signature | ||
281 | */ | ||
282 | struct GNUNET_CRYPTO_EccSignature * | ||
283 | GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_EccPrivateKey *key, | ||
284 | struct GNUNET_TIME_Absolute expire, | ||
285 | const char *name, | ||
286 | const struct GNUNET_NAMESTORE_RecordData *rd, | ||
287 | unsigned int rd_count) | ||
288 | { | ||
289 | struct GNUNET_CRYPTO_EccSignature *sig; | ||
290 | struct GNUNET_CRYPTO_EccSignaturePurpose *sig_purpose; | ||
291 | struct GNUNET_TIME_AbsoluteNBO expire_nbo; | ||
292 | size_t rd_ser_len; | ||
293 | size_t name_len; | ||
294 | struct GNUNET_TIME_AbsoluteNBO *expire_tmp; | ||
295 | char * name_tmp; | ||
296 | char * rd_tmp; | ||
297 | int res; | ||
298 | uint32_t sig_len; | ||
299 | |||
300 | if (NULL == name) | ||
301 | { | ||
302 | GNUNET_break (0); | ||
303 | return NULL; | ||
304 | } | ||
305 | sig = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignature)); | ||
306 | name_len = strlen (name) + 1; | ||
307 | expire_nbo = GNUNET_TIME_absolute_hton (expire); | ||
308 | rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); | ||
309 | { | ||
310 | char rd_ser[rd_ser_len]; | ||
311 | |||
312 | GNUNET_assert (rd_ser_len == | ||
313 | GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); | ||
314 | sig_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; | ||
315 | sig_purpose = GNUNET_malloc (sig_len); | ||
316 | sig_purpose->size = htonl (sig_len); | ||
317 | sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
318 | expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; | ||
319 | memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); | ||
320 | name_tmp = (char *) &expire_tmp[1]; | ||
321 | memcpy (name_tmp, name, name_len); | ||
322 | rd_tmp = &name_tmp[name_len]; | ||
323 | memcpy (rd_tmp, rd_ser, rd_ser_len); | ||
324 | res = GNUNET_CRYPTO_ecc_sign (key, sig_purpose, sig); | ||
325 | GNUNET_free (sig_purpose); | ||
326 | } | ||
327 | if (GNUNET_OK != res) | ||
328 | { | ||
329 | GNUNET_break (0); | ||
330 | GNUNET_free (sig); | ||
331 | return NULL; | ||
332 | } | ||
333 | return sig; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Convert the 'value' of a record to a string. | ||
339 | * | ||
340 | * @param type type of the record | ||
341 | * @param data value in binary encoding | ||
342 | * @param data_size number of bytes in data | ||
343 | * @return NULL on error, otherwise human-readable representation of the value | ||
344 | */ | ||
345 | char * | ||
346 | GNUNET_NAMESTORE_value_to_string (uint32_t type, | ||
347 | const void *data, | ||
348 | size_t data_size) | ||
349 | { | ||
350 | uint16_t mx_pref; | ||
351 | const struct soa_data *soa; | ||
352 | const struct vpn_data *vpn; | ||
353 | const struct srv_data *srv; | ||
354 | const struct tlsa_data *tlsa; | ||
355 | struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; | ||
356 | struct GNUNET_CRYPTO_HashAsciiEncoded s_peer; | ||
357 | const char *cdata; | ||
358 | char* vpn_str; | ||
359 | char* srv_str; | ||
360 | char* tlsa_str; | ||
361 | char* result; | ||
362 | const char* soa_rname; | ||
363 | const char* soa_mname; | ||
364 | char tmp[INET6_ADDRSTRLEN]; | ||
365 | |||
366 | switch (type) | ||
367 | { | ||
368 | case 0: | ||
369 | return NULL; | ||
370 | case GNUNET_DNSPARSER_TYPE_A: | ||
371 | if (data_size != sizeof (struct in_addr)) | ||
372 | return NULL; | ||
373 | if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp))) | ||
374 | return NULL; | ||
375 | return GNUNET_strdup (tmp); | ||
376 | case GNUNET_DNSPARSER_TYPE_NS: | ||
377 | return GNUNET_strndup (data, data_size); | ||
378 | case GNUNET_DNSPARSER_TYPE_CNAME: | ||
379 | return GNUNET_strndup (data, data_size); | ||
380 | case GNUNET_DNSPARSER_TYPE_SOA: | ||
381 | if (data_size <= sizeof (struct soa_data)) | ||
382 | return NULL; | ||
383 | soa = data; | ||
384 | soa_rname = (const char*) &soa[1]; | ||
385 | soa_mname = memchr (soa_rname, 0, data_size - sizeof (struct soa_data) - 1); | ||
386 | if (NULL == soa_mname) | ||
387 | return NULL; | ||
388 | soa_mname++; | ||
389 | if (NULL == memchr (soa_mname, 0, | ||
390 | data_size - (sizeof (struct soa_data) + strlen (soa_rname) + 1))) | ||
391 | return NULL; | ||
392 | GNUNET_asprintf (&result, | ||
393 | "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu", | ||
394 | soa_rname, soa_mname, | ||
395 | ntohl (soa->serial), | ||
396 | ntohl (soa->refresh), | ||
397 | ntohl (soa->retry), | ||
398 | ntohl (soa->expire), | ||
399 | ntohl (soa->minimum)); | ||
400 | return result; | ||
401 | case GNUNET_DNSPARSER_TYPE_PTR: | ||
402 | return GNUNET_strndup (data, data_size); | ||
403 | case GNUNET_DNSPARSER_TYPE_MX: | ||
404 | mx_pref = ntohs(*((uint16_t*)data)); | ||
405 | if (GNUNET_asprintf(&result, "%hu,%s", mx_pref, data+sizeof(uint16_t)) | ||
406 | != 0) | ||
407 | return result; | ||
408 | else | ||
409 | { | ||
410 | GNUNET_free (result); | ||
411 | return NULL; | ||
412 | } | ||
413 | case GNUNET_DNSPARSER_TYPE_TXT: | ||
414 | return GNUNET_strndup (data, data_size); | ||
415 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
416 | if (data_size != sizeof (struct in6_addr)) | ||
417 | return NULL; | ||
418 | if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp))) | ||
419 | return NULL; | ||
420 | return GNUNET_strdup (tmp); | ||
421 | case GNUNET_NAMESTORE_TYPE_PKEY: | ||
422 | if (data_size != sizeof (struct GNUNET_CRYPTO_ShortHashCode)) | ||
423 | return NULL; | ||
424 | GNUNET_CRYPTO_short_hash_to_enc (data, | ||
425 | &enc); | ||
426 | return GNUNET_strdup ((const char*) enc.short_encoding); | ||
427 | case GNUNET_NAMESTORE_TYPE_PSEU: | ||
428 | return GNUNET_strndup (data, data_size); | ||
429 | case GNUNET_NAMESTORE_TYPE_LEHO: | ||
430 | return GNUNET_strndup (data, data_size); | ||
431 | case GNUNET_NAMESTORE_TYPE_VPN: | ||
432 | cdata = data; | ||
433 | if ( (data_size <= sizeof (struct vpn_data)) || | ||
434 | ('\0' != cdata[data_size - 1]) ) | ||
435 | return NULL; /* malformed */ | ||
436 | vpn = data; | ||
437 | GNUNET_CRYPTO_hash_to_enc (&vpn->peer, &s_peer); | ||
438 | if (0 == GNUNET_asprintf (&vpn_str, "%u %s %s", | ||
439 | (unsigned int) ntohs (vpn->proto), | ||
440 | (const char*) &s_peer, | ||
441 | (const char*) &vpn[1])) | ||
442 | { | ||
443 | GNUNET_free (vpn_str); | ||
444 | return NULL; | ||
445 | } | ||
446 | return vpn_str; | ||
447 | case GNUNET_DNSPARSER_TYPE_SRV: | ||
448 | cdata = data; | ||
449 | if ( (data_size <= sizeof (struct srv_data)) || | ||
450 | ('\0' != cdata[data_size - 1]) ) | ||
451 | return NULL; /* malformed */ | ||
452 | srv = data; | ||
453 | |||
454 | if (0 == GNUNET_asprintf (&srv_str, | ||
455 | "%d %d %d %s", | ||
456 | ntohs (srv->prio), | ||
457 | ntohs (srv->weight), | ||
458 | ntohs (srv->port), | ||
459 | (const char *)&srv[1])) | ||
460 | { | ||
461 | GNUNET_free (srv_str); | ||
462 | return NULL; | ||
463 | } | ||
464 | return srv_str; | ||
465 | case GNUNET_DNSPARSER_TYPE_TLSA: | ||
466 | cdata = data; | ||
467 | if ( (data_size <= sizeof (struct tlsa_data)) || | ||
468 | ('\0' != cdata[data_size - 1]) ) | ||
469 | return NULL; /* malformed */ | ||
470 | tlsa = data; | ||
471 | if (0 == GNUNET_asprintf (&tlsa_str, | ||
472 | "%c %c %c %s", | ||
473 | tlsa->usage, | ||
474 | tlsa->selector, | ||
475 | tlsa->matching_type, | ||
476 | (const char *) &tlsa[1])) | ||
477 | { | ||
478 | GNUNET_free (tlsa_str); | ||
479 | return NULL; | ||
480 | } | ||
481 | return tlsa_str; | ||
482 | default: | ||
483 | GNUNET_break (0); | ||
484 | } | ||
485 | GNUNET_break (0); // not implemented | ||
486 | return NULL; | ||
487 | } | ||
488 | |||
489 | |||
490 | /** | ||
491 | * Convert human-readable version of a 'value' of a record to the binary | ||
492 | * representation. | ||
493 | * | ||
494 | * @param type type of the record | ||
495 | * @param s human-readable string | ||
496 | * @param data set to value in binary encoding (will be allocated) | ||
497 | * @param data_size set to number of bytes in data | ||
498 | * @return GNUNET_OK on success | ||
499 | */ | ||
500 | int | ||
501 | GNUNET_NAMESTORE_string_to_value (uint32_t type, | ||
502 | const char *s, | ||
503 | void **data, | ||
504 | size_t *data_size) | ||
505 | { | ||
506 | struct in_addr value_a; | ||
507 | struct in6_addr value_aaaa; | ||
508 | struct GNUNET_CRYPTO_ShortHashCode pkey; | ||
509 | struct soa_data *soa; | ||
510 | struct vpn_data *vpn; | ||
511 | struct tlsa_data *tlsa; | ||
512 | char result[253 + 1]; | ||
513 | char soa_rname[253 + 1]; | ||
514 | char soa_mname[253 + 1]; | ||
515 | char s_peer[103 + 1]; | ||
516 | char s_serv[253 + 1]; | ||
517 | unsigned int soa_serial; | ||
518 | unsigned int soa_refresh; | ||
519 | unsigned int soa_retry; | ||
520 | unsigned int soa_expire; | ||
521 | unsigned int soa_min; | ||
522 | uint16_t mx_pref; | ||
523 | uint16_t mx_pref_n; | ||
524 | unsigned int proto; | ||
525 | |||
526 | if (NULL == s) | ||
527 | return GNUNET_SYSERR; | ||
528 | switch (type) | ||
529 | { | ||
530 | case 0: | ||
531 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
532 | _("Unsupported record type %d\n"), | ||
533 | (int) type); | ||
534 | return GNUNET_SYSERR; | ||
535 | case GNUNET_DNSPARSER_TYPE_A: | ||
536 | if (1 != inet_pton (AF_INET, s, &value_a)) | ||
537 | { | ||
538 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
539 | _("Unable to parse IPv4 address `%s'\n"), | ||
540 | s); | ||
541 | return GNUNET_SYSERR; | ||
542 | } | ||
543 | *data = GNUNET_malloc (sizeof (struct in_addr)); | ||
544 | memcpy (*data, &value_a, sizeof (value_a)); | ||
545 | *data_size = sizeof (value_a); | ||
546 | return GNUNET_OK; | ||
547 | case GNUNET_DNSPARSER_TYPE_NS: | ||
548 | *data = GNUNET_strdup (s); | ||
549 | *data_size = strlen (s) + 1; | ||
550 | return GNUNET_OK; | ||
551 | case GNUNET_DNSPARSER_TYPE_CNAME: | ||
552 | *data = GNUNET_strdup (s); | ||
553 | *data_size = strlen (s) + 1; | ||
554 | return GNUNET_OK; | ||
555 | case GNUNET_DNSPARSER_TYPE_SOA: | ||
556 | if (7 != SSCANF (s, | ||
557 | "rname=%253s mname=%253s %u,%u,%u,%u,%u", | ||
558 | soa_rname, soa_mname, | ||
559 | &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min)) | ||
560 | { | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
562 | _("Unable to parse SOA record `%s'\n"), | ||
563 | s); | ||
564 | return GNUNET_SYSERR; | ||
565 | } | ||
566 | *data_size = sizeof (struct soa_data)+strlen(soa_rname)+strlen(soa_mname)+2; | ||
567 | *data = GNUNET_malloc (*data_size); | ||
568 | soa = (struct soa_data*)*data; | ||
569 | soa->serial = htonl(soa_serial); | ||
570 | soa->refresh = htonl(soa_refresh); | ||
571 | soa->retry = htonl(soa_retry); | ||
572 | soa->expire = htonl(soa_expire); | ||
573 | soa->minimum = htonl(soa_min); | ||
574 | strcpy((char*)&soa[1], soa_rname); | ||
575 | strcpy((char*)&soa[1]+strlen(*data)+1, soa_mname); | ||
576 | return GNUNET_OK; | ||
577 | case GNUNET_DNSPARSER_TYPE_PTR: | ||
578 | *data = GNUNET_strdup (s); | ||
579 | *data_size = strlen (s); | ||
580 | return GNUNET_OK; | ||
581 | case GNUNET_DNSPARSER_TYPE_MX: | ||
582 | if (2 != SSCANF(s, "%hu,%253s", &mx_pref, result)) | ||
583 | { | ||
584 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
585 | _("Unable to parse MX record `%s'\n"), | ||
586 | s); | ||
587 | return GNUNET_SYSERR; | ||
588 | } | ||
589 | *data_size = sizeof (uint16_t)+strlen(result)+1; | ||
590 | *data = GNUNET_malloc (*data_size); | ||
591 | mx_pref_n = htons(mx_pref); | ||
592 | memcpy(*data, &mx_pref_n, sizeof (uint16_t)); | ||
593 | strcpy((*data)+sizeof (uint16_t), result); | ||
594 | return GNUNET_OK; | ||
595 | case GNUNET_DNSPARSER_TYPE_TXT: | ||
596 | *data = GNUNET_strdup (s); | ||
597 | *data_size = strlen (s); | ||
598 | return GNUNET_OK; | ||
599 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
600 | if (1 != inet_pton (AF_INET6, s, &value_aaaa)) | ||
601 | { | ||
602 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
603 | _("Unable to parse IPv6 address `%s'\n"), | ||
604 | s); | ||
605 | return GNUNET_SYSERR; | ||
606 | } | ||
607 | *data = GNUNET_malloc (sizeof (struct in6_addr)); | ||
608 | *data_size = sizeof (struct in6_addr); | ||
609 | memcpy (*data, &value_aaaa, sizeof (value_aaaa)); | ||
610 | return GNUNET_OK; | ||
611 | case GNUNET_NAMESTORE_TYPE_PKEY: | ||
612 | if (GNUNET_OK != | ||
613 | GNUNET_CRYPTO_short_hash_from_string (s, &pkey)) | ||
614 | { | ||
615 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
616 | _("Unable to parse PKEY record `%s'\n"), | ||
617 | s); | ||
618 | return GNUNET_SYSERR; | ||
619 | } | ||
620 | *data = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); | ||
621 | memcpy (*data, &pkey, sizeof (pkey)); | ||
622 | *data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode); | ||
623 | return GNUNET_OK; | ||
624 | case GNUNET_NAMESTORE_TYPE_PSEU: | ||
625 | *data = GNUNET_strdup (s); | ||
626 | *data_size = strlen (s); | ||
627 | return GNUNET_OK; | ||
628 | case GNUNET_NAMESTORE_TYPE_LEHO: | ||
629 | *data = GNUNET_strdup (s); | ||
630 | *data_size = strlen (s); | ||
631 | return GNUNET_OK; | ||
632 | case GNUNET_NAMESTORE_TYPE_VPN: | ||
633 | if (3 != SSCANF (s,"%u %103s %253s", | ||
634 | &proto, s_peer, s_serv)) | ||
635 | { | ||
636 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
637 | _("Unable to parse VPN record string `%s'\n"), | ||
638 | s); | ||
639 | return GNUNET_SYSERR; | ||
640 | } | ||
641 | *data_size = sizeof (struct vpn_data) + strlen (s_serv) + 1; | ||
642 | *data = vpn = GNUNET_malloc (*data_size); | ||
643 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_peer, | ||
644 | &vpn->peer)) | ||
645 | { | ||
646 | GNUNET_free (vpn); | ||
647 | *data_size = 0; | ||
648 | return GNUNET_SYSERR; | ||
649 | } | ||
650 | vpn->proto = htons ((uint16_t) proto); | ||
651 | strcpy ((char*)&vpn[1], s_serv); | ||
652 | return GNUNET_OK; | ||
653 | case GNUNET_DNSPARSER_TYPE_TLSA: | ||
654 | *data_size = sizeof (struct tlsa_data) + strlen (s) - 6; | ||
655 | *data = tlsa = GNUNET_malloc (*data_size); | ||
656 | if (4 != SSCANF (s, "%c %c %c %s", | ||
657 | &tlsa->usage, | ||
658 | &tlsa->selector, | ||
659 | &tlsa->matching_type, | ||
660 | (char*)&tlsa[1])) | ||
661 | { | ||
662 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
663 | _("Unable to parse TLSA record string `%s'\n"), | ||
664 | s); | ||
665 | *data_size = 0; | ||
666 | GNUNET_free (tlsa); | ||
667 | return GNUNET_SYSERR; | ||
668 | } | ||
669 | return GNUNET_OK; | ||
670 | default: | ||
671 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
672 | _("Unsupported record type %d\n"), | ||
673 | (int) type); | ||
674 | return GNUNET_SYSERR; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | |||
679 | static struct { | ||
680 | const char *name; | ||
681 | uint32_t number; | ||
682 | } name_map[] = { | ||
683 | { "A", GNUNET_DNSPARSER_TYPE_A }, | ||
684 | { "NS", GNUNET_DNSPARSER_TYPE_NS }, | ||
685 | { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME }, | ||
686 | { "SOA", GNUNET_DNSPARSER_TYPE_SOA }, | ||
687 | { "PTR", GNUNET_DNSPARSER_TYPE_PTR }, | ||
688 | { "MX", GNUNET_DNSPARSER_TYPE_MX }, | ||
689 | { "TXT", GNUNET_DNSPARSER_TYPE_TXT }, | ||
690 | { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA }, | ||
691 | { "PKEY", GNUNET_NAMESTORE_TYPE_PKEY }, | ||
692 | { "PSEU", GNUNET_NAMESTORE_TYPE_PSEU }, | ||
693 | { "LEHO", GNUNET_NAMESTORE_TYPE_LEHO }, | ||
694 | { "VPN", GNUNET_NAMESTORE_TYPE_VPN }, | ||
695 | { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA }, | ||
696 | { NULL, UINT32_MAX } | ||
697 | }; | ||
698 | |||
699 | |||
700 | /** | ||
701 | * Convert a type name (i.e. "AAAA") to the corresponding number. | ||
702 | * | ||
703 | * @param typename name to convert | ||
704 | * @return corresponding number, UINT32_MAX on error | ||
705 | */ | ||
706 | uint32_t | ||
707 | GNUNET_NAMESTORE_typename_to_number (const char *typename) | ||
708 | { | ||
709 | unsigned int i; | ||
710 | |||
711 | i=0; | ||
712 | while ( (name_map[i].name != NULL) && | ||
713 | (0 != strcasecmp (typename, name_map[i].name)) ) | ||
714 | i++; | ||
715 | return name_map[i].number; | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") | ||
721 | * | ||
722 | * @param type number of a type to convert | ||
723 | * @return corresponding typestring, NULL on error | ||
724 | */ | ||
725 | const char * | ||
726 | GNUNET_NAMESTORE_number_to_typename (uint32_t type) | ||
727 | { | ||
728 | unsigned int i; | ||
729 | |||
730 | i=0; | ||
731 | while ( (name_map[i].name != NULL) && | ||
732 | (type != name_map[i].number) ) | ||
733 | i++; | ||
734 | return name_map[i].name; | ||
735 | } | ||
736 | |||
737 | /** | ||
738 | * Test if a given record is expired. | ||
739 | * | ||
740 | * @return GNUNET_YES if the record is expired, | ||
741 | * GNUNET_NO if not | ||
742 | */ | ||
743 | int | ||
744 | GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd) | ||
745 | { | ||
746 | struct GNUNET_TIME_Absolute at; | ||
747 | |||
748 | if (0 != (rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) | ||
749 | return GNUNET_NO; | ||
750 | at.abs_value = rd->expiration_time; | ||
751 | return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value) ? GNUNET_YES : GNUNET_NO; | ||
752 | } | ||
753 | |||
754 | |||
755 | /* end of namestore_common.c */ | ||