gnunet-service-gns.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011-2018 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 gns/gnunet-service-gns.c
  18. * @brief GNU Name System (main service)
  19. * @author Martin Schanzenbach
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_dns_service.h"
  25. #include "gnunet_dnsparser_lib.h"
  26. #include "gnunet_dht_service.h"
  27. #include "gnunet_namecache_service.h"
  28. #include "gnunet_gnsrecord_lib.h"
  29. #include "gnunet_gns_service.h"
  30. #include "gnunet_statistics_service.h"
  31. #include "gns.h"
  32. #include "gnunet-service-gns_resolver.h"
  33. #include "gnunet-service-gns_interceptor.h"
  34. #include "gnunet_protocols.h"
  35. /**
  36. * GnsClient prototype
  37. */
  38. struct GnsClient;
  39. /**
  40. * Handle to a lookup operation from client via API.
  41. */
  42. struct ClientLookupHandle
  43. {
  44. /**
  45. * We keep these in a DLL.
  46. */
  47. struct ClientLookupHandle *next;
  48. /**
  49. * We keep these in a DLL.
  50. */
  51. struct ClientLookupHandle *prev;
  52. /**
  53. * Client handle
  54. */
  55. struct GnsClient *gc;
  56. /**
  57. * Active handle for the lookup.
  58. */
  59. struct GNS_ResolverHandle *lookup;
  60. /**
  61. * request id
  62. */
  63. uint32_t request_id;
  64. };
  65. /**
  66. * Information we track per connected client.
  67. */
  68. struct GnsClient
  69. {
  70. /**
  71. * The client
  72. */
  73. struct GNUNET_SERVICE_Client *client;
  74. /**
  75. * The MQ
  76. */
  77. struct GNUNET_MQ_Handle *mq;
  78. /**
  79. * Head of the DLL.
  80. */
  81. struct ClientLookupHandle *clh_head;
  82. /**
  83. * Tail of the DLL.
  84. */
  85. struct ClientLookupHandle *clh_tail;
  86. };
  87. /**
  88. * Representation of a TLD, mapping the respective TLD string
  89. * (e.g. ".gnu") to the respective public key of the zone.
  90. */
  91. struct GNS_TopLevelDomain
  92. {
  93. /**
  94. * Kept in a DLL, as there are unlikely enough of these to
  95. * warrant a hash map.
  96. */
  97. struct GNS_TopLevelDomain *next;
  98. /**
  99. * Kept in a DLL, as there are unlikely enough of these to
  100. * warrant a hash map.
  101. */
  102. struct GNS_TopLevelDomain *prev;
  103. /**
  104. * Public key associated with the @a tld.
  105. */
  106. struct GNUNET_IDENTITY_PublicKey pkey;
  107. /**
  108. * Top-level domain as a string, including leading ".".
  109. */
  110. char *tld;
  111. };
  112. /**
  113. * Our handle to the DHT
  114. */
  115. static struct GNUNET_DHT_Handle *dht_handle;
  116. /**
  117. * Our handle to the namecache service
  118. */
  119. static struct GNUNET_NAMECACHE_Handle *namecache_handle;
  120. /**
  121. * #GNUNET_YES if ipv6 is supported
  122. */
  123. static int v6_enabled;
  124. /**
  125. * #GNUNET_YES if ipv4 is supported
  126. */
  127. static int v4_enabled;
  128. /**
  129. * Handle to the statistics service
  130. */
  131. static struct GNUNET_STATISTICS_Handle *statistics;
  132. /**
  133. * Head of DLL of TLDs we map to GNS zones.
  134. */
  135. static struct GNS_TopLevelDomain *tld_head;
  136. /**
  137. * Tail of DLL of TLDs we map to GNS zones.
  138. */
  139. static struct GNS_TopLevelDomain *tld_tail;
  140. /**
  141. * Find GNS zone belonging to TLD @a tld.
  142. *
  143. * @param tld_str top-level domain to look up
  144. * @param[out] pkey public key to set
  145. * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not
  146. */
  147. int
  148. GNS_find_tld (const char *tld_str,
  149. struct GNUNET_IDENTITY_PublicKey *pkey)
  150. {
  151. if ('\0' == *tld_str)
  152. return GNUNET_NO;
  153. for (struct GNS_TopLevelDomain *tld = tld_head;
  154. NULL != tld;
  155. tld = tld->next)
  156. {
  157. if (0 == strcasecmp (tld_str,
  158. tld->tld))
  159. {
  160. *pkey = tld->pkey;
  161. return GNUNET_YES;
  162. }
  163. }
  164. if (GNUNET_OK ==
  165. GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1,
  166. pkey))
  167. return GNUNET_YES; /* TLD string *was* the public key */
  168. return GNUNET_NO;
  169. }
  170. /**
  171. * Obtain the TLD of the given @a name.
  172. *
  173. * @param name a name
  174. * @return the part of @a name after the last ".",
  175. * or @a name if @a name does not contain a "."
  176. */
  177. const char *
  178. GNS_get_tld (const char *name)
  179. {
  180. const char *tld;
  181. tld = strrchr (name,
  182. (unsigned char) '.');
  183. if (NULL == tld)
  184. tld = name;
  185. else
  186. tld++; /* skip the '.' */
  187. return tld;
  188. }
  189. /**
  190. * Task run during shutdown.
  191. *
  192. * @param cls unused, NULL
  193. */
  194. static void
  195. shutdown_task (void *cls)
  196. {
  197. struct GNS_TopLevelDomain *tld;
  198. (void) cls;
  199. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  200. "Shutting down!\n");
  201. GNS_interceptor_done ();
  202. GNS_resolver_done ();
  203. if (NULL != statistics)
  204. {
  205. GNUNET_STATISTICS_destroy (statistics,
  206. GNUNET_NO);
  207. statistics = NULL;
  208. }
  209. if (NULL != namecache_handle)
  210. {
  211. GNUNET_NAMECACHE_disconnect (namecache_handle);
  212. namecache_handle = NULL;
  213. }
  214. if (NULL != dht_handle)
  215. {
  216. GNUNET_DHT_disconnect (dht_handle);
  217. dht_handle = NULL;
  218. }
  219. while (NULL != (tld = tld_head))
  220. {
  221. GNUNET_CONTAINER_DLL_remove (tld_head,
  222. tld_tail,
  223. tld);
  224. GNUNET_free (tld->tld);
  225. GNUNET_free (tld);
  226. }
  227. }
  228. /**
  229. * Called whenever a client is disconnected.
  230. *
  231. * @param cls closure
  232. * @param client identification of the client
  233. * @param app_ctx @a client
  234. */
  235. static void
  236. client_disconnect_cb (void *cls,
  237. struct GNUNET_SERVICE_Client *client,
  238. void *app_ctx)
  239. {
  240. struct ClientLookupHandle *clh;
  241. struct GnsClient *gc = app_ctx;
  242. (void) cls;
  243. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  244. "Client %p disconnected\n",
  245. client);
  246. while (NULL != (clh = gc->clh_head))
  247. {
  248. if (NULL != clh->lookup)
  249. GNS_resolver_lookup_cancel (clh->lookup);
  250. GNUNET_CONTAINER_DLL_remove (gc->clh_head,
  251. gc->clh_tail,
  252. clh);
  253. GNUNET_free (clh);
  254. }
  255. GNUNET_free (gc);
  256. }
  257. /**
  258. * Add a client to our list of active clients.
  259. *
  260. * @param cls NULL
  261. * @param client client to add
  262. * @param mq message queue for @a client
  263. * @return internal namestore client structure for this client
  264. */
  265. static void *
  266. client_connect_cb (void *cls,
  267. struct GNUNET_SERVICE_Client *client,
  268. struct GNUNET_MQ_Handle *mq)
  269. {
  270. struct GnsClient *gc;
  271. (void) cls;
  272. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  273. "Client %p connected\n",
  274. client);
  275. gc = GNUNET_new (struct GnsClient);
  276. gc->client = client;
  277. gc->mq = mq;
  278. return gc;
  279. }
  280. /**
  281. * Reply to client with the result from our lookup.
  282. *
  283. * @param cls the closure (our client lookup handle)
  284. * @param rd_count the number of records in @a rd
  285. * @param rd the record data
  286. */
  287. static void
  288. send_lookup_response (void *cls,
  289. uint32_t rd_count,
  290. const struct GNUNET_GNSRECORD_Data *rd)
  291. {
  292. struct ClientLookupHandle *clh = cls;
  293. struct GnsClient *gc = clh->gc;
  294. struct GNUNET_MQ_Envelope *env;
  295. struct LookupResultMessage *rmsg;
  296. ssize_t len;
  297. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  298. "Sending LOOKUP_RESULT message with %u results\n",
  299. (unsigned int) rd_count);
  300. len = GNUNET_GNSRECORD_records_get_size (rd_count,
  301. rd);
  302. if (len < 0)
  303. {
  304. GNUNET_break (0);
  305. GNUNET_SERVICE_client_drop (gc->client);
  306. return;
  307. }
  308. if (len > UINT16_MAX - sizeof(*rmsg))
  309. {
  310. GNUNET_break (0);
  311. GNUNET_SERVICE_client_drop (gc->client);
  312. return;
  313. }
  314. env = GNUNET_MQ_msg_extra (rmsg,
  315. len,
  316. GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
  317. rmsg->id = clh->request_id;
  318. rmsg->rd_count = htonl (rd_count);
  319. GNUNET_assert (len ==
  320. GNUNET_GNSRECORD_records_serialize (rd_count,
  321. rd,
  322. len,
  323. (char *) &rmsg[1]));
  324. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (gc->client),
  325. env);
  326. GNUNET_CONTAINER_DLL_remove (gc->clh_head,
  327. gc->clh_tail,
  328. clh);
  329. GNUNET_free (clh);
  330. GNUNET_STATISTICS_update (statistics,
  331. "Completed lookups", 1,
  332. GNUNET_NO);
  333. GNUNET_STATISTICS_update (statistics,
  334. "Records resolved",
  335. rd_count,
  336. GNUNET_NO);
  337. }
  338. /**
  339. * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
  340. *
  341. * @param cls client sending the message
  342. * @param l_msg message of type `struct LookupMessage`
  343. * @return #GNUNET_OK if @a l_msg is well-formed
  344. */
  345. static int
  346. check_lookup (void *cls,
  347. const struct LookupMessage *l_msg)
  348. {
  349. size_t nlen;
  350. (void) cls;
  351. GNUNET_MQ_check_zero_termination (l_msg);
  352. nlen = ntohs (l_msg->header.size) - sizeof(struct LookupMessage);
  353. if (nlen > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
  354. {
  355. GNUNET_break (0);
  356. return GNUNET_SYSERR;
  357. }
  358. return GNUNET_OK;
  359. }
  360. /**
  361. * Handle lookup requests from client
  362. *
  363. * @param cls the closure
  364. * @param client the client
  365. * @param message the message
  366. */
  367. static void
  368. handle_lookup (void *cls,
  369. const struct LookupMessage *sh_msg)
  370. {
  371. struct GnsClient *gc = cls;
  372. char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
  373. struct ClientLookupHandle *clh;
  374. char *nameptr = name;
  375. const char *utf_in;
  376. GNUNET_SERVICE_client_continue (gc->client);
  377. utf_in = (const char *) &sh_msg[1];
  378. GNUNET_STRINGS_utf8_tolower (utf_in,
  379. nameptr);
  380. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  381. "Received LOOKUP `%s' message\n",
  382. name);
  383. clh = GNUNET_new (struct ClientLookupHandle);
  384. GNUNET_CONTAINER_DLL_insert (gc->clh_head,
  385. gc->clh_tail,
  386. clh);
  387. clh->gc = gc;
  388. clh->request_id = sh_msg->id;
  389. if ((GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
  390. (GNUNET_OK != v4_enabled))
  391. {
  392. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  393. "LOOKUP: Query for A record but AF_INET not supported!");
  394. send_lookup_response (clh,
  395. 0,
  396. NULL);
  397. return;
  398. }
  399. if ((GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
  400. (GNUNET_OK != v6_enabled))
  401. {
  402. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  403. "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
  404. send_lookup_response (clh,
  405. 0,
  406. NULL);
  407. return;
  408. }
  409. clh->lookup = GNS_resolver_lookup (&sh_msg->zone,
  410. ntohl (sh_msg->type),
  411. name,
  412. (enum GNUNET_GNS_LocalOptions) ntohs (
  413. sh_msg->options),
  414. ntohs (sh_msg->recursion_depth_limit),
  415. &send_lookup_response, clh);
  416. GNUNET_STATISTICS_update (statistics,
  417. "Lookup attempts",
  418. 1, GNUNET_NO);
  419. }
  420. /**
  421. * Reads the configuration and populates TLDs
  422. *
  423. * @param cls unused
  424. * @param section name of section in config, always "gns"
  425. * @param option name of the option, TLDs start with "."
  426. * @param value value for the option, public key for TLDs
  427. */
  428. static void
  429. read_service_conf (void *cls,
  430. const char *section,
  431. const char *option,
  432. const char *value)
  433. {
  434. struct GNUNET_IDENTITY_PublicKey pk;
  435. struct GNS_TopLevelDomain *tld;
  436. (void) cls;
  437. (void) section;
  438. if (option[0] != '.')
  439. return;
  440. if (GNUNET_OK !=
  441. GNUNET_STRINGS_string_to_data (value,
  442. strlen (value),
  443. &pk,
  444. sizeof(pk)))
  445. {
  446. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  447. section,
  448. option,
  449. _ (
  450. "Properly base32-encoded public key required"));
  451. return;
  452. }
  453. tld = GNUNET_new (struct GNS_TopLevelDomain);
  454. tld->tld = GNUNET_strdup (&option[1]);
  455. tld->pkey = pk;
  456. GNUNET_CONTAINER_DLL_insert (tld_head,
  457. tld_tail,
  458. tld);
  459. }
  460. /**
  461. * Process GNS requests.
  462. *
  463. * @param cls closure
  464. * @param server the initialized server
  465. * @param c configuration to use
  466. */
  467. static void
  468. run (void *cls,
  469. const struct GNUNET_CONFIGURATION_Handle *c,
  470. struct GNUNET_SERVICE_Handle *service)
  471. {
  472. unsigned long long max_parallel_bg_queries = 16;
  473. GNUNET_CONFIGURATION_iterate_section_values (c,
  474. "gns",
  475. &read_service_conf,
  476. NULL);
  477. v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
  478. v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
  479. namecache_handle = GNUNET_NAMECACHE_connect (c);
  480. if (NULL == namecache_handle)
  481. {
  482. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  483. _ ("Failed to connect to the namecache!\n"));
  484. GNUNET_SCHEDULER_shutdown ();
  485. return;
  486. }
  487. if (GNUNET_OK ==
  488. GNUNET_CONFIGURATION_get_value_number (c,
  489. "gns",
  490. "MAX_PARALLEL_BACKGROUND_QUERIES",
  491. &max_parallel_bg_queries))
  492. {
  493. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  494. "Number of allowed parallel background queries: %llu\n",
  495. max_parallel_bg_queries);
  496. }
  497. dht_handle = GNUNET_DHT_connect (c,
  498. (unsigned int) max_parallel_bg_queries);
  499. if (NULL == dht_handle)
  500. {
  501. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  502. _ ("Could not connect to DHT!\n"));
  503. GNUNET_SCHEDULER_add_now (&shutdown_task,
  504. NULL);
  505. return;
  506. }
  507. GNS_resolver_init (namecache_handle,
  508. dht_handle,
  509. c,
  510. max_parallel_bg_queries);
  511. if ((GNUNET_YES ==
  512. GNUNET_CONFIGURATION_get_value_yesno (c,
  513. "gns",
  514. "INTERCEPT_DNS")) &&
  515. (GNUNET_SYSERR ==
  516. GNS_interceptor_init (c)))
  517. {
  518. GNUNET_break (0);
  519. GNUNET_SCHEDULER_add_now (&shutdown_task,
  520. NULL);
  521. return;
  522. }
  523. statistics = GNUNET_STATISTICS_create ("gns",
  524. c);
  525. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  526. NULL);
  527. }
  528. /**
  529. * Define "main" method using service macro.
  530. */
  531. GNUNET_SERVICE_MAIN
  532. ("gns",
  533. GNUNET_SERVICE_OPTION_NONE,
  534. &run,
  535. &client_connect_cb,
  536. &client_disconnect_cb,
  537. NULL,
  538. GNUNET_MQ_hd_var_size (lookup,
  539. GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
  540. struct LookupMessage,
  541. NULL),
  542. GNUNET_MQ_handler_end ());
  543. /* end of gnunet-service-gns.c */