plugin_gnsrecord_dns.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2013, 2014 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file gnsrecord/plugin_gnsrecord_dns.c
  18. * @brief gnsrecord plugin to provide the API for basic DNS records
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_dnsparser_lib.h"
  24. #include "gnunet_gnsrecord_plugin.h"
  25. /**
  26. * Convert the 'value' of a record to a string.
  27. *
  28. * @param cls closure, unused
  29. * @param type type of the record
  30. * @param data value in binary encoding
  31. * @param data_size number of bytes in @a data
  32. * @return NULL on error, otherwise human-readable representation of the value
  33. */
  34. static char *
  35. dns_value_to_string (void *cls,
  36. uint32_t type,
  37. const void *data,
  38. size_t data_size)
  39. {
  40. char *result;
  41. char tmp[INET6_ADDRSTRLEN];
  42. switch (type)
  43. {
  44. case GNUNET_DNSPARSER_TYPE_A:
  45. if (data_size != sizeof(struct in_addr))
  46. return NULL;
  47. if (NULL == inet_ntop (AF_INET, data, tmp, sizeof(tmp)))
  48. return NULL;
  49. return GNUNET_strdup (tmp);
  50. case GNUNET_DNSPARSER_TYPE_NS: {
  51. char *ns;
  52. size_t off;
  53. off = 0;
  54. ns = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
  55. if ((NULL == ns) || (off != data_size))
  56. {
  57. GNUNET_break_op (0);
  58. GNUNET_free_non_null (ns);
  59. return NULL;
  60. }
  61. return ns;
  62. }
  63. case GNUNET_DNSPARSER_TYPE_CNAME: {
  64. char *cname;
  65. size_t off;
  66. off = 0;
  67. cname = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
  68. if ((NULL == cname) || (off != data_size))
  69. {
  70. GNUNET_break_op (0);
  71. GNUNET_free_non_null (cname);
  72. return NULL;
  73. }
  74. return cname;
  75. }
  76. case GNUNET_DNSPARSER_TYPE_SOA: {
  77. struct GNUNET_DNSPARSER_SoaRecord *soa;
  78. size_t off;
  79. off = 0;
  80. soa = GNUNET_DNSPARSER_parse_soa (data, data_size, &off);
  81. if ((NULL == soa) || (off != data_size))
  82. {
  83. GNUNET_break_op (0);
  84. if (NULL != soa)
  85. GNUNET_DNSPARSER_free_soa (soa);
  86. return NULL;
  87. }
  88. GNUNET_asprintf (&result,
  89. "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
  90. soa->rname,
  91. soa->mname,
  92. soa->serial,
  93. soa->refresh,
  94. soa->retry,
  95. soa->expire,
  96. soa->minimum_ttl);
  97. GNUNET_DNSPARSER_free_soa (soa);
  98. return result;
  99. }
  100. case GNUNET_DNSPARSER_TYPE_PTR: {
  101. char *ptr;
  102. size_t off;
  103. off = 0;
  104. ptr = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
  105. if ((NULL == ptr) || (off != data_size))
  106. {
  107. GNUNET_break_op (0);
  108. GNUNET_free_non_null (ptr);
  109. return NULL;
  110. }
  111. return ptr;
  112. }
  113. case GNUNET_DNSPARSER_TYPE_CERT: {
  114. struct GNUNET_DNSPARSER_CertRecord *cert;
  115. size_t off;
  116. char *base64;
  117. int len;
  118. off = 0;
  119. cert = GNUNET_DNSPARSER_parse_cert (data, data_size, &off);
  120. if ((NULL == cert) || (off != data_size))
  121. {
  122. GNUNET_break_op (0);
  123. GNUNET_DNSPARSER_free_cert (cert);
  124. return NULL;
  125. }
  126. len = GNUNET_STRINGS_base64_encode (cert->certificate_data,
  127. cert->certificate_size,
  128. &base64);
  129. GNUNET_asprintf (&result,
  130. "%u %u %u %.*s",
  131. cert->cert_type,
  132. cert->cert_tag,
  133. cert->algorithm,
  134. len,
  135. base64);
  136. GNUNET_free (base64);
  137. GNUNET_DNSPARSER_free_cert (cert);
  138. return result;
  139. }
  140. case GNUNET_DNSPARSER_TYPE_MX: {
  141. struct GNUNET_DNSPARSER_MxRecord *mx;
  142. size_t off;
  143. off = 0;
  144. mx = GNUNET_DNSPARSER_parse_mx (data, data_size, &off);
  145. if ((NULL == mx) || (off != data_size))
  146. {
  147. GNUNET_break_op (0);
  148. GNUNET_DNSPARSER_free_mx (mx);
  149. return NULL;
  150. }
  151. GNUNET_asprintf (&result,
  152. "%u,%s",
  153. (unsigned int) mx->preference,
  154. mx->mxhost);
  155. GNUNET_DNSPARSER_free_mx (mx);
  156. return result;
  157. }
  158. case GNUNET_DNSPARSER_TYPE_TXT:
  159. return GNUNET_strndup (data, data_size);
  160. case GNUNET_DNSPARSER_TYPE_AAAA:
  161. if (data_size != sizeof(struct in6_addr))
  162. return NULL;
  163. if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof(tmp)))
  164. return NULL;
  165. return GNUNET_strdup (tmp);
  166. case GNUNET_DNSPARSER_TYPE_SRV: {
  167. struct GNUNET_DNSPARSER_SrvRecord *srv;
  168. size_t off;
  169. off = 0;
  170. srv = GNUNET_DNSPARSER_parse_srv (data, data_size, &off);
  171. if ((NULL == srv) || (off != data_size))
  172. {
  173. GNUNET_break_op (0);
  174. if (NULL != srv)
  175. GNUNET_DNSPARSER_free_srv (srv);
  176. return NULL;
  177. }
  178. GNUNET_asprintf (&result,
  179. "%d %d %d %s",
  180. srv->priority,
  181. srv->weight,
  182. srv->port,
  183. srv->target);
  184. GNUNET_DNSPARSER_free_srv (srv);
  185. return result;
  186. }
  187. case GNUNET_DNSPARSER_TYPE_TLSA: {
  188. const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
  189. char *tlsa_str;
  190. char *hex;
  191. if (data_size < sizeof(struct GNUNET_TUN_DnsTlsaRecord))
  192. return NULL; /* malformed */
  193. tlsa = data;
  194. hex =
  195. GNUNET_DNSPARSER_bin_to_hex (&tlsa[1],
  196. data_size
  197. - sizeof(struct GNUNET_TUN_DnsTlsaRecord));
  198. if (0 == GNUNET_asprintf (&tlsa_str,
  199. "%u %u %u %s",
  200. (unsigned int) tlsa->usage,
  201. (unsigned int) tlsa->selector,
  202. (unsigned int) tlsa->matching_type,
  203. hex))
  204. {
  205. GNUNET_free (hex);
  206. GNUNET_free (tlsa_str);
  207. return NULL;
  208. }
  209. GNUNET_free (hex);
  210. return tlsa_str;
  211. }
  212. case GNUNET_DNSPARSER_TYPE_CAA: { // RFC6844
  213. const struct GNUNET_DNSPARSER_CaaRecord *caa;
  214. char tag[15]; // between 1 and 15 bytes
  215. char value[data_size];
  216. char *caa_str;
  217. if (data_size < sizeof(struct GNUNET_DNSPARSER_CaaRecord))
  218. return NULL; /* malformed */
  219. caa = data;
  220. if ((1 > caa->tag_len) || (15 < caa->tag_len))
  221. return NULL; /* malformed */
  222. memset (tag, 0, sizeof(tag));
  223. memset (value, 0, data_size);
  224. memcpy (tag, &caa[1], caa->tag_len);
  225. memcpy (value,
  226. (char *) &caa[1] + caa->tag_len,
  227. data_size - caa->tag_len - 2);
  228. if (0 == GNUNET_asprintf (&caa_str,
  229. "%u %s %s",
  230. (unsigned int) caa->flags,
  231. tag,
  232. value))
  233. {
  234. GNUNET_free (caa_str);
  235. return NULL;
  236. }
  237. return caa_str;
  238. }
  239. default:
  240. return NULL;
  241. }
  242. }
  243. /**
  244. * Convert RFC 4394 Mnemonics to the corresponding integer values.
  245. *
  246. * @param mnemonic string to look up
  247. * @return the value, 0 if not found
  248. */
  249. static unsigned int
  250. rfc4398_mnemonic_to_value (const char *mnemonic)
  251. {
  252. static struct
  253. {
  254. const char *mnemonic;
  255. unsigned int val;
  256. } table[] = { { "PKIX", 1 },
  257. { "SPKI", 2 },
  258. { "PGP", 3 },
  259. { "IPKIX", 4 },
  260. { "ISPKI", 5 },
  261. { "IPGP", 6 },
  262. { "ACPKIX", 7 },
  263. { "IACPKIX", 8 },
  264. { "URI", 253 },
  265. { "OID", 254 },
  266. { NULL, 0 } };
  267. unsigned int i;
  268. for (i = 0; NULL != table[i].mnemonic; i++)
  269. if (0 == strcasecmp (mnemonic, table[i].mnemonic))
  270. return table[i].val;
  271. return 0;
  272. }
  273. /**
  274. * Convert RFC 4034 algorithm types to the corresponding integer values.
  275. *
  276. * @param mnemonic string to look up
  277. * @return the value, 0 if not found
  278. */
  279. static unsigned int
  280. rfc4034_mnemonic_to_value (const char *mnemonic)
  281. {
  282. static struct
  283. {
  284. const char *mnemonic;
  285. unsigned int val;
  286. } table[] = { { "RSAMD5", 1 },
  287. { "DH", 2 },
  288. { "DSA", 3 },
  289. { "ECC", 4 },
  290. { "RSASHA1", 5 },
  291. { "INDIRECT", 252 },
  292. { "PRIVATEDNS", 253 },
  293. { "PRIVATEOID", 254 },
  294. { NULL, 0 } };
  295. unsigned int i;
  296. for (i = 0; NULL != table[i].mnemonic; i++)
  297. if (0 == strcasecmp (mnemonic, table[i].mnemonic))
  298. return table[i].val;
  299. return 0;
  300. }
  301. /**
  302. * Convert human-readable version of a 'value' of a record to the binary
  303. * representation.
  304. *
  305. * @param cls closure, unused
  306. * @param type type of the record
  307. * @param s human-readable string
  308. * @param data set to value in binary encoding (will be allocated)
  309. * @param data_size set to number of bytes in @a data
  310. * @return #GNUNET_OK on success
  311. */
  312. static int
  313. dns_string_to_value (void *cls,
  314. uint32_t type,
  315. const char *s,
  316. void **data,
  317. size_t *data_size)
  318. {
  319. struct in_addr value_a;
  320. struct in6_addr value_aaaa;
  321. struct GNUNET_TUN_DnsTlsaRecord *tlsa;
  322. if (NULL == s)
  323. return GNUNET_SYSERR;
  324. switch (type)
  325. {
  326. case GNUNET_DNSPARSER_TYPE_A:
  327. if (1 != inet_pton (AF_INET, s, &value_a))
  328. {
  329. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  330. _ ("Unable to parse IPv4 address `%s'\n"),
  331. s);
  332. return GNUNET_SYSERR;
  333. }
  334. *data = GNUNET_new (struct in_addr);
  335. GNUNET_memcpy (*data, &value_a, sizeof(value_a));
  336. *data_size = sizeof(value_a);
  337. return GNUNET_OK;
  338. case GNUNET_DNSPARSER_TYPE_NS: {
  339. char nsbuf[256];
  340. size_t off;
  341. off = 0;
  342. if (GNUNET_OK !=
  343. GNUNET_DNSPARSER_builder_add_name (nsbuf, sizeof(nsbuf), &off, s))
  344. {
  345. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  346. _ ("Failed to serialize NS record with value `%s'\n"),
  347. s);
  348. return GNUNET_SYSERR;
  349. }
  350. *data_size = off;
  351. *data = GNUNET_malloc (off);
  352. GNUNET_memcpy (*data, nsbuf, off);
  353. return GNUNET_OK;
  354. }
  355. case GNUNET_DNSPARSER_TYPE_CNAME: {
  356. char cnamebuf[256];
  357. size_t off;
  358. off = 0;
  359. if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_name (cnamebuf,
  360. sizeof(cnamebuf),
  361. &off,
  362. s))
  363. {
  364. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  365. _ ("Failed to serialize CNAME record with value `%s'\n"),
  366. s);
  367. return GNUNET_SYSERR;
  368. }
  369. *data_size = off;
  370. *data = GNUNET_malloc (off);
  371. GNUNET_memcpy (*data, cnamebuf, off);
  372. return GNUNET_OK;
  373. }
  374. case GNUNET_DNSPARSER_TYPE_CERT: {
  375. char *sdup;
  376. const char *typep;
  377. const char *keyp;
  378. const char *algp;
  379. const char *certp;
  380. unsigned int type;
  381. unsigned int key;
  382. unsigned int alg;
  383. size_t cert_size;
  384. char *cert_data;
  385. struct GNUNET_DNSPARSER_CertRecord cert;
  386. sdup = GNUNET_strdup (s);
  387. typep = strtok (sdup, " ");
  388. if ((NULL == typep) ||
  389. ((0 == (type = rfc4398_mnemonic_to_value (typep))) &&
  390. ((1 != sscanf (typep, "%u", &type)) || (type > UINT16_MAX))))
  391. {
  392. GNUNET_free (sdup);
  393. return GNUNET_SYSERR;
  394. }
  395. keyp = strtok (NULL, " ");
  396. if ((NULL == keyp) || (1 != sscanf (keyp, "%u", &key)) ||
  397. (key > UINT16_MAX))
  398. {
  399. GNUNET_free (sdup);
  400. return GNUNET_SYSERR;
  401. }
  402. alg = 0;
  403. algp = strtok (NULL, " ");
  404. if ((NULL == algp) ||
  405. ((0 == (type = rfc4034_mnemonic_to_value (typep))) &&
  406. ((1 != sscanf (algp, "%u", &alg)) || (alg > UINT8_MAX))))
  407. {
  408. GNUNET_free (sdup);
  409. return GNUNET_SYSERR;
  410. }
  411. certp = strtok (NULL, " ");
  412. if ((NULL == certp) || (0 == strlen (certp)))
  413. {
  414. GNUNET_free (sdup);
  415. return GNUNET_SYSERR;
  416. }
  417. cert_size = GNUNET_STRINGS_base64_decode (certp,
  418. strlen (certp),
  419. (void **) &cert_data);
  420. GNUNET_free (sdup);
  421. cert.cert_type = type;
  422. cert.cert_tag = key;
  423. cert.algorithm = alg;
  424. cert.certificate_size = cert_size;
  425. cert.certificate_data = cert_data;
  426. {
  427. char certbuf[cert_size + sizeof(struct GNUNET_TUN_DnsCertRecord)];
  428. size_t off;
  429. off = 0;
  430. if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_cert (certbuf,
  431. sizeof(certbuf),
  432. &off,
  433. &cert))
  434. {
  435. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  436. _ ("Failed to serialize CERT record with %u bytes\n"),
  437. (unsigned int) cert_size);
  438. GNUNET_free (cert_data);
  439. return GNUNET_SYSERR;
  440. }
  441. *data_size = off;
  442. *data = GNUNET_malloc (off);
  443. GNUNET_memcpy (*data, certbuf, off);
  444. }
  445. GNUNET_free (cert_data);
  446. return GNUNET_OK;
  447. }
  448. case GNUNET_DNSPARSER_TYPE_SOA: {
  449. struct GNUNET_DNSPARSER_SoaRecord soa;
  450. char soabuf[540];
  451. char soa_rname[253 + 1];
  452. char soa_mname[253 + 1];
  453. unsigned int soa_serial;
  454. unsigned int soa_refresh;
  455. unsigned int soa_retry;
  456. unsigned int soa_expire;
  457. unsigned int soa_min;
  458. size_t off;
  459. if (7 != sscanf (s,
  460. "rname=%253s mname=%253s %u,%u,%u,%u,%u",
  461. soa_rname,
  462. soa_mname,
  463. &soa_serial,
  464. &soa_refresh,
  465. &soa_retry,
  466. &soa_expire,
  467. &soa_min))
  468. {
  469. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  470. _ ("Unable to parse SOA record `%s'\n"),
  471. s);
  472. return GNUNET_SYSERR;
  473. }
  474. soa.mname = soa_mname;
  475. soa.rname = soa_rname;
  476. soa.serial = (uint32_t) soa_serial;
  477. soa.refresh = (uint32_t) soa_refresh;
  478. soa.retry = (uint32_t) soa_retry;
  479. soa.expire = (uint32_t) soa_expire;
  480. soa.minimum_ttl = (uint32_t) soa_min;
  481. off = 0;
  482. if (GNUNET_OK !=
  483. GNUNET_DNSPARSER_builder_add_soa (soabuf, sizeof(soabuf), &off, &soa))
  484. {
  485. GNUNET_log (
  486. GNUNET_ERROR_TYPE_ERROR,
  487. _ ("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
  488. soa_mname,
  489. soa_rname);
  490. return GNUNET_SYSERR;
  491. }
  492. *data_size = off;
  493. *data = GNUNET_malloc (off);
  494. GNUNET_memcpy (*data, soabuf, off);
  495. return GNUNET_OK;
  496. }
  497. case GNUNET_DNSPARSER_TYPE_PTR: {
  498. char ptrbuf[256];
  499. size_t off;
  500. off = 0;
  501. if (GNUNET_OK !=
  502. GNUNET_DNSPARSER_builder_add_name (ptrbuf, sizeof(ptrbuf), &off, s))
  503. {
  504. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  505. _ ("Failed to serialize PTR record with value `%s'\n"),
  506. s);
  507. return GNUNET_SYSERR;
  508. }
  509. *data_size = off;
  510. *data = GNUNET_malloc (off);
  511. GNUNET_memcpy (*data, ptrbuf, off);
  512. return GNUNET_OK;
  513. }
  514. case GNUNET_DNSPARSER_TYPE_MX: {
  515. struct GNUNET_DNSPARSER_MxRecord mx;
  516. char mxbuf[258];
  517. char mxhost[253 + 1];
  518. unsigned int mx_pref;
  519. size_t off;
  520. if (2 != sscanf (s, "%u,%253s", &mx_pref, mxhost))
  521. {
  522. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  523. _ ("Unable to parse MX record `%s'\n"),
  524. s);
  525. return GNUNET_SYSERR;
  526. }
  527. mx.preference = (uint16_t) mx_pref;
  528. mx.mxhost = mxhost;
  529. off = 0;
  530. if (GNUNET_OK !=
  531. GNUNET_DNSPARSER_builder_add_mx (mxbuf, sizeof(mxbuf), &off, &mx))
  532. {
  533. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  534. _ ("Failed to serialize MX record with hostname `%s'\n"),
  535. mxhost);
  536. return GNUNET_SYSERR;
  537. }
  538. *data_size = off;
  539. *data = GNUNET_malloc (off);
  540. GNUNET_memcpy (*data, mxbuf, off);
  541. return GNUNET_OK;
  542. }
  543. case GNUNET_DNSPARSER_TYPE_SRV: {
  544. struct GNUNET_DNSPARSER_SrvRecord srv;
  545. char srvbuf[270];
  546. char srvtarget[253 + 1];
  547. unsigned int priority;
  548. unsigned int weight;
  549. unsigned int port;
  550. size_t off;
  551. if (4 != sscanf (s, "%u %u %u %253s", &priority, &weight, &port,
  552. srvtarget))
  553. {
  554. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  555. _ ("Unable to parse SRV record `%s'\n"),
  556. s);
  557. return GNUNET_SYSERR;
  558. }
  559. srv.priority = (uint16_t) priority;
  560. srv.weight = (uint16_t) weight;
  561. srv.port = (uint16_t) port;
  562. srv.target = srvtarget;
  563. off = 0;
  564. if (GNUNET_OK !=
  565. GNUNET_DNSPARSER_builder_add_srv (srvbuf, sizeof(srvbuf), &off, &srv))
  566. {
  567. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  568. _ ("Failed to serialize SRV record with target `%s'\n"),
  569. srvtarget);
  570. return GNUNET_SYSERR;
  571. }
  572. *data_size = off;
  573. *data = GNUNET_malloc (off);
  574. GNUNET_memcpy (*data, srvbuf, off);
  575. return GNUNET_OK;
  576. }
  577. case GNUNET_DNSPARSER_TYPE_TXT:
  578. *data = GNUNET_strdup (s);
  579. *data_size = strlen (s);
  580. return GNUNET_OK;
  581. case GNUNET_DNSPARSER_TYPE_AAAA:
  582. if (1 != inet_pton (AF_INET6, s, &value_aaaa))
  583. {
  584. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  585. _ ("Unable to parse IPv6 address `%s'\n"),
  586. s);
  587. return GNUNET_SYSERR;
  588. }
  589. *data = GNUNET_new (struct in6_addr);
  590. *data_size = sizeof(struct in6_addr);
  591. GNUNET_memcpy (*data, &value_aaaa, sizeof(value_aaaa));
  592. return GNUNET_OK;
  593. case GNUNET_DNSPARSER_TYPE_TLSA: {
  594. unsigned int usage;
  595. unsigned int selector;
  596. unsigned int matching_type;
  597. size_t slen = strlen (s) + 1;
  598. char hex[slen];
  599. if (4 != sscanf (s, "%u %u %u %s", &usage, &selector, &matching_type,
  600. hex))
  601. {
  602. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  603. _ ("Unable to parse TLSA record string `%s'\n"),
  604. s);
  605. *data_size = 0;
  606. return GNUNET_SYSERR;
  607. }
  608. *data_size = sizeof(struct GNUNET_TUN_DnsTlsaRecord) + strlen (hex) / 2;
  609. *data = tlsa = GNUNET_malloc (*data_size);
  610. tlsa->usage = (uint8_t) usage;
  611. tlsa->selector = (uint8_t) selector;
  612. tlsa->matching_type = (uint8_t) matching_type;
  613. if (strlen (hex) / 2 != GNUNET_DNSPARSER_hex_to_bin (hex, &tlsa[1]))
  614. {
  615. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  616. _ ("Unable to parse TLSA record string `%s'\n"),
  617. s);
  618. GNUNET_free (*data);
  619. *data = NULL;
  620. *data_size = 0;
  621. return GNUNET_SYSERR;
  622. }
  623. return GNUNET_OK;
  624. }
  625. case GNUNET_DNSPARSER_TYPE_CAA: { // RFC6844
  626. struct GNUNET_DNSPARSER_CaaRecord *caa;
  627. unsigned int flags;
  628. char tag[15]; // Max tag length 15
  629. char value[strlen (s) + 1]; // Should be more than enough
  630. if (3 != sscanf (s, "%u %s %[^\n]", &flags, tag, value))
  631. {
  632. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  633. _ ("Unable to parse CAA record string `%s'\n"),
  634. s);
  635. *data_size = 0;
  636. return GNUNET_SYSERR;
  637. }
  638. *data_size = sizeof(struct GNUNET_DNSPARSER_CaaRecord) + strlen (tag)
  639. + strlen (value);
  640. *data = caa = GNUNET_malloc (*data_size);
  641. caa->flags = flags;
  642. memcpy (&caa[1], tag, strlen (tag));
  643. caa->tag_len = strlen (tag);
  644. memcpy ((char *) &caa[1] + caa->tag_len, value, strlen (value));
  645. return GNUNET_OK;
  646. }
  647. default:
  648. return GNUNET_SYSERR;
  649. }
  650. }
  651. /**
  652. * Mapping of record type numbers to human-readable
  653. * record type names.
  654. */
  655. static struct
  656. {
  657. const char *name;
  658. uint32_t number;
  659. } name_map[] = { { "A", GNUNET_DNSPARSER_TYPE_A },
  660. { "NS", GNUNET_DNSPARSER_TYPE_NS },
  661. { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
  662. { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
  663. { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
  664. { "MX", GNUNET_DNSPARSER_TYPE_MX },
  665. { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
  666. { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
  667. { "SRV", GNUNET_DNSPARSER_TYPE_SRV },
  668. { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
  669. { "CERT", GNUNET_DNSPARSER_TYPE_CERT },
  670. { "CAA", GNUNET_DNSPARSER_TYPE_CAA },
  671. { NULL, UINT32_MAX } };
  672. /**
  673. * Convert a type name (i.e. "AAAA") to the corresponding number.
  674. *
  675. * @param cls closure, unused
  676. * @param dns_typename name to convert
  677. * @return corresponding number, UINT32_MAX on error
  678. */
  679. static uint32_t
  680. dns_typename_to_number (void *cls, const char *dns_typename)
  681. {
  682. unsigned int i;
  683. i = 0;
  684. while ((NULL != name_map[i].name) &&
  685. (0 != strcasecmp (dns_typename, name_map[i].name)))
  686. i++;
  687. return name_map[i].number;
  688. }
  689. /**
  690. * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
  691. *
  692. * @param cls closure, unused
  693. * @param type number of a type to convert
  694. * @return corresponding typestring, NULL on error
  695. */
  696. static const char *
  697. dns_number_to_typename (void *cls, uint32_t type)
  698. {
  699. unsigned int i;
  700. i = 0;
  701. while ((NULL != name_map[i].name) && (type != name_map[i].number))
  702. i++;
  703. return name_map[i].name;
  704. }
  705. /**
  706. * Entry point for the plugin.
  707. *
  708. * @param cls NULL
  709. * @return the exported block API
  710. */
  711. void *
  712. libgnunet_plugin_gnsrecord_dns_init (void *cls)
  713. {
  714. struct GNUNET_GNSRECORD_PluginFunctions *api;
  715. api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
  716. api->value_to_string = &dns_value_to_string;
  717. api->string_to_value = &dns_string_to_value;
  718. api->typename_to_number = &dns_typename_to_number;
  719. api->number_to_typename = &dns_number_to_typename;
  720. return api;
  721. }
  722. /**
  723. * Exit point from the plugin.
  724. *
  725. * @param cls the return value from #libgnunet_plugin_block_test_init
  726. * @return NULL
  727. */
  728. void *
  729. libgnunet_plugin_gnsrecord_dns_done (void *cls)
  730. {
  731. struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
  732. GNUNET_free (api);
  733. return NULL;
  734. }
  735. /* end of plugin_gnsrecord_dns.c */