vpn_api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2016 Christian Grothoff
  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 vpn/vpn_api.c
  18. * @brief library to access the VPN service and tell it how to redirect traffic
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_vpn_service.h"
  23. #include "vpn.h"
  24. /**
  25. * Opaque VPN handle
  26. */
  27. struct GNUNET_VPN_Handle
  28. {
  29. /**
  30. * Configuration we use.
  31. */
  32. const struct GNUNET_CONFIGURATION_Handle *cfg;
  33. /**
  34. * Connection to VPN service.
  35. */
  36. struct GNUNET_MQ_Handle *mq;
  37. /**
  38. * Head of list of active redirection requests.
  39. */
  40. struct GNUNET_VPN_RedirectionRequest *rr_head;
  41. /**
  42. * Tail of list of active redirection requests.
  43. */
  44. struct GNUNET_VPN_RedirectionRequest *rr_tail;
  45. /**
  46. * Identifier of a reconnect task.
  47. */
  48. struct GNUNET_SCHEDULER_Task *rt;
  49. /**
  50. * How long do we wait until we try to reconnect?
  51. */
  52. struct GNUNET_TIME_Relative backoff;
  53. /**
  54. * ID of the last request that was submitted to the service.
  55. */
  56. uint64_t request_id_gen;
  57. };
  58. /**
  59. * Opaque redirection request handle.
  60. */
  61. struct GNUNET_VPN_RedirectionRequest
  62. {
  63. /**
  64. * Element in DLL.
  65. */
  66. struct GNUNET_VPN_RedirectionRequest *next;
  67. /**
  68. * Element in DLL.
  69. */
  70. struct GNUNET_VPN_RedirectionRequest *prev;
  71. /**
  72. * Pointer to the VPN struct.
  73. */
  74. struct GNUNET_VPN_Handle *vh;
  75. /**
  76. * Target IP address for the redirection, or NULL for
  77. * redirection to service. Allocated after this struct.
  78. */
  79. const void *addr;
  80. /**
  81. * Function to call with the designated IP address.
  82. */
  83. GNUNET_VPN_AllocationCallback cb;
  84. /**
  85. * Closure for @e cb.
  86. */
  87. void *cb_cls;
  88. /**
  89. * For service redirection, identity of the peer offering the service.
  90. */
  91. struct GNUNET_PeerIdentity peer;
  92. /**
  93. * For service redirection, service descriptor.
  94. */
  95. struct GNUNET_HashCode serv;
  96. /**
  97. * At what time should the created service mapping expire?
  98. */
  99. struct GNUNET_TIME_Absolute expiration_time;
  100. /**
  101. * non-zero if this request has been sent to the service.
  102. */
  103. uint64_t request_id;
  104. /**
  105. * Desired address family for the result.
  106. */
  107. int result_af;
  108. /**
  109. * Address family of @e addr. AF_INET or AF_INET6.
  110. */
  111. int addr_af;
  112. /**
  113. * For service redirection, IPPROT_UDP or IPPROTO_TCP.
  114. */
  115. uint8_t protocol;
  116. };
  117. /**
  118. * Disconnect from the service (communication error) and reconnect later.
  119. *
  120. * @param vh handle to reconnect.
  121. */
  122. static void
  123. reconnect (struct GNUNET_VPN_Handle *vh);
  124. /**
  125. * Check a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
  126. * VPN service.
  127. *
  128. * @param cls the `struct GNUNET_VPN_Handle`
  129. * @param rm message received
  130. * @return #GNUNET_OK if @a rm is well-formed
  131. */
  132. static int
  133. check_use_ip (void *cls,
  134. const struct RedirectToIpResponseMessage *rm)
  135. {
  136. size_t alen;
  137. int af;
  138. af = (int) ntohl (rm->result_af);
  139. switch (af)
  140. {
  141. case AF_UNSPEC:
  142. alen = 0;
  143. break;
  144. case AF_INET:
  145. alen = sizeof(struct in_addr);
  146. break;
  147. case AF_INET6:
  148. alen = sizeof(struct in6_addr);
  149. break;
  150. default:
  151. GNUNET_break (0);
  152. return GNUNET_SYSERR;
  153. }
  154. if ((ntohs (rm->header.size) != alen + sizeof(*rm)) ||
  155. (0 == rm->request_id))
  156. {
  157. GNUNET_break (0);
  158. return GNUNET_SYSERR;
  159. }
  160. return GNUNET_OK;
  161. }
  162. /**
  163. * Handle a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
  164. * VPN service.
  165. *
  166. * @param cls the `struct GNUNET_VPN_Handle`
  167. * @param rm message received
  168. */
  169. static void
  170. handle_use_ip (void *cls,
  171. const struct RedirectToIpResponseMessage *rm)
  172. {
  173. struct GNUNET_VPN_Handle *vh = cls;
  174. struct GNUNET_VPN_RedirectionRequest *rr;
  175. int af;
  176. af = (int) ntohl (rm->result_af);
  177. for (rr = vh->rr_head; NULL != rr; rr = rr->next)
  178. {
  179. if (rr->request_id == rm->request_id)
  180. {
  181. GNUNET_CONTAINER_DLL_remove (vh->rr_head,
  182. vh->rr_tail,
  183. rr);
  184. rr->cb (rr->cb_cls,
  185. af,
  186. (af == AF_UNSPEC) ? NULL : &rm[1]);
  187. GNUNET_free (rr);
  188. break;
  189. }
  190. }
  191. }
  192. /**
  193. * Add a request to our request queue and transmit it.
  194. *
  195. * @param rr request to queue and transmit.
  196. */
  197. static void
  198. send_request (struct GNUNET_VPN_RedirectionRequest *rr)
  199. {
  200. struct GNUNET_VPN_Handle *vh = rr->vh;
  201. struct RedirectToIpRequestMessage *rip;
  202. struct RedirectToServiceRequestMessage *rs;
  203. struct GNUNET_MQ_Envelope *env;
  204. size_t alen;
  205. if (NULL == vh->mq)
  206. return;
  207. if (NULL == rr->addr)
  208. {
  209. env = GNUNET_MQ_msg (rs,
  210. GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE);
  211. rs->reserved = htonl (0);
  212. rs->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
  213. rs->protocol = htonl (rr->protocol);
  214. rs->result_af = htonl (rr->result_af);
  215. rs->target = rr->peer;
  216. rs->service_descriptor = rr->serv;
  217. rs->request_id = rr->request_id = ++vh->request_id_gen;
  218. }
  219. else
  220. {
  221. switch (rr->addr_af)
  222. {
  223. case AF_INET:
  224. alen = sizeof(struct in_addr);
  225. break;
  226. case AF_INET6:
  227. alen = sizeof(struct in6_addr);
  228. break;
  229. default:
  230. GNUNET_assert (0);
  231. return;
  232. }
  233. env = GNUNET_MQ_msg_extra (rip,
  234. alen,
  235. GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP);
  236. rip->reserved = htonl (0);
  237. rip->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
  238. rip->result_af = htonl (rr->result_af);
  239. rip->addr_af = htonl (rr->addr_af);
  240. rip->request_id = rr->request_id = ++vh->request_id_gen;
  241. GNUNET_memcpy (&rip[1],
  242. rr->addr,
  243. alen);
  244. }
  245. GNUNET_MQ_send (vh->mq,
  246. env);
  247. }
  248. /**
  249. * Generic error handler, called with the appropriate error code and
  250. * the same closure specified at the creation of the message queue.
  251. * Not every message queue implementation supports an error handler.
  252. *
  253. * @param cls closure with the `struct GNUNET_VPN_Handle *`
  254. * @param error error code
  255. */
  256. static void
  257. mq_error_handler (void *cls,
  258. enum GNUNET_MQ_Error error)
  259. {
  260. struct GNUNET_VPN_Handle *vh = cls;
  261. reconnect (vh);
  262. }
  263. /**
  264. * Connect to the VPN service and start again to transmit our requests.
  265. *
  266. * @param cls the `struct GNUNET_VPN_Handle *`
  267. */
  268. static void
  269. connect_task (void *cls)
  270. {
  271. struct GNUNET_VPN_Handle *vh = cls;
  272. struct GNUNET_MQ_MessageHandler handlers[] = {
  273. GNUNET_MQ_hd_var_size (use_ip,
  274. GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP,
  275. struct RedirectToIpResponseMessage,
  276. cls),
  277. GNUNET_MQ_handler_end ()
  278. };
  279. struct GNUNET_VPN_RedirectionRequest *rr;
  280. vh->rt = NULL;
  281. vh->mq = GNUNET_CLIENT_connect (vh->cfg,
  282. "vpn",
  283. handlers,
  284. &mq_error_handler,
  285. vh);
  286. if (NULL == vh->mq)
  287. return;
  288. for (rr = vh->rr_head; NULL != rr; rr = rr->next)
  289. send_request (rr);
  290. }
  291. /**
  292. * Disconnect from the service (communication error) and reconnect later.
  293. *
  294. * @param vh handle to reconnect.
  295. */
  296. static void
  297. reconnect (struct GNUNET_VPN_Handle *vh)
  298. {
  299. struct GNUNET_VPN_RedirectionRequest *rr;
  300. GNUNET_MQ_destroy (vh->mq);
  301. vh->mq = NULL;
  302. vh->request_id_gen = 0;
  303. for (rr = vh->rr_head; NULL != rr; rr = rr->next)
  304. rr->request_id = 0;
  305. vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS,
  306. GNUNET_TIME_relative_min (
  307. GNUNET_TIME_relative_saturating_multiply (
  308. vh->backoff, 2),
  309. GNUNET_TIME_relative_multiply (
  310. GNUNET_TIME_UNIT_SECONDS, 30)));
  311. vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff,
  312. &connect_task,
  313. vh);
  314. }
  315. /**
  316. * Cancel redirection request with the service.
  317. *
  318. * @param rr request to cancel
  319. */
  320. void
  321. GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr)
  322. {
  323. struct GNUNET_VPN_Handle *vh;
  324. vh = rr->vh;
  325. GNUNET_CONTAINER_DLL_remove (vh->rr_head,
  326. vh->rr_tail,
  327. rr);
  328. GNUNET_free (rr);
  329. }
  330. /**
  331. * Tell the VPN that a forwarding to a particular peer offering a
  332. * particular service is requested. The VPN is to reserve a
  333. * particular IP for the redirection and return it. The VPN will
  334. * begin the redirection as soon as possible and maintain it as long
  335. * as it is actively used and keeping it is feasible. Given resource
  336. * limitations, the longest inactive mappings will be destroyed.
  337. *
  338. * @param vh VPN handle
  339. * @param result_af desired address family for the returned allocation
  340. * can also be AF_UNSPEC
  341. * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP
  342. * @param peer target peer for the redirection
  343. * @param serv service descriptor to give to the peer
  344. * @param expiration_time at what time should the redirection expire?
  345. * (this should not impact connections that are active at that time)
  346. * @param cb function to call with the IP
  347. * @param cb_cls closure for @a cb
  348. * @return handle to cancel the request (means the callback won't be
  349. * invoked anymore; the mapping may or may not be established
  350. * anyway)
  351. */
  352. struct GNUNET_VPN_RedirectionRequest *
  353. GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh,
  354. int result_af,
  355. uint8_t protocol,
  356. const struct GNUNET_PeerIdentity *peer,
  357. const struct GNUNET_HashCode *serv,
  358. struct GNUNET_TIME_Absolute expiration_time,
  359. GNUNET_VPN_AllocationCallback cb,
  360. void *cb_cls)
  361. {
  362. struct GNUNET_VPN_RedirectionRequest *rr;
  363. rr = GNUNET_new (struct GNUNET_VPN_RedirectionRequest);
  364. rr->vh = vh;
  365. rr->cb = cb;
  366. rr->cb_cls = cb_cls;
  367. rr->peer = *peer;
  368. rr->serv = *serv;
  369. rr->expiration_time = expiration_time;
  370. rr->result_af = result_af;
  371. rr->protocol = protocol;
  372. GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
  373. vh->rr_tail,
  374. rr);
  375. send_request (rr);
  376. return rr;
  377. }
  378. /**
  379. * Tell the VPN that forwarding to the Internet via some exit node is
  380. * requested. Note that both UDP and TCP traffic will be forwarded,
  381. * but possibly to different exit nodes. The VPN is to reserve a
  382. * particular IP for the redirection and return it. The VPN will
  383. * begin the redirection as soon as possible and maintain it as long
  384. * as it is actively used and keeping it is feasible. Given resource
  385. * limitations, the longest inactive mappings will be destroyed.
  386. *
  387. * @param vh VPN handle
  388. * @param result_af desired address family for the returned allocation
  389. * @param addr_af address family for @a addr, AF_INET or AF_INET6
  390. * @param addr destination IP address on the Internet; destination
  391. * port is to be taken from the VPN packet itself
  392. * @param expiration_time at what time should the redirection expire?
  393. * (this should not impact connections that are active at that time)
  394. * @param cb function to call with the IP
  395. * @param cb_cls closure for @a cb
  396. * @return handle to cancel the request (means the callback won't be
  397. * invoked anymore; the mapping may or may not be established
  398. * anyway)
  399. */
  400. struct GNUNET_VPN_RedirectionRequest *
  401. GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh,
  402. int result_af,
  403. int addr_af,
  404. const void *addr,
  405. struct GNUNET_TIME_Absolute expiration_time,
  406. GNUNET_VPN_AllocationCallback cb,
  407. void *cb_cls)
  408. {
  409. struct GNUNET_VPN_RedirectionRequest *rr;
  410. size_t alen;
  411. switch (addr_af)
  412. {
  413. case AF_INET:
  414. alen = sizeof(struct in_addr);
  415. break;
  416. case AF_INET6:
  417. alen = sizeof(struct in6_addr);
  418. break;
  419. default:
  420. GNUNET_break (0);
  421. return NULL;
  422. }
  423. rr = GNUNET_malloc (sizeof(struct GNUNET_VPN_RedirectionRequest) + alen);
  424. rr->vh = vh;
  425. rr->addr = &rr[1];
  426. rr->cb = cb;
  427. rr->cb_cls = cb_cls;
  428. rr->expiration_time = expiration_time;
  429. rr->result_af = result_af;
  430. rr->addr_af = addr_af;
  431. GNUNET_memcpy (&rr[1],
  432. addr,
  433. alen);
  434. GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
  435. vh->rr_tail,
  436. rr);
  437. send_request (rr);
  438. return rr;
  439. }
  440. /**
  441. * Connect to the VPN service
  442. *
  443. * @param cfg configuration to use
  444. * @return VPN handle
  445. */
  446. struct GNUNET_VPN_Handle *
  447. GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
  448. {
  449. struct GNUNET_VPN_Handle *vh
  450. = GNUNET_new (struct GNUNET_VPN_Handle);
  451. vh->cfg = cfg;
  452. connect_task (vh);
  453. if (NULL == vh->mq)
  454. {
  455. GNUNET_free (vh);
  456. return NULL;
  457. }
  458. return vh;
  459. }
  460. /**
  461. * Disconnect from the VPN service.
  462. *
  463. * @param vh VPN handle
  464. */
  465. void
  466. GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh)
  467. {
  468. GNUNET_assert (NULL == vh->rr_head);
  469. if (NULL != vh->mq)
  470. {
  471. GNUNET_MQ_destroy (vh->mq);
  472. vh->mq = NULL;
  473. }
  474. if (NULL != vh->rt)
  475. {
  476. GNUNET_SCHEDULER_cancel (vh->rt);
  477. vh->rt = NULL;
  478. }
  479. GNUNET_free (vh);
  480. }
  481. /* end of vpn_api.c */