gnunet-service-nat.c 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2016, 2017 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 nat/gnunet-service-nat.c
  18. * @brief network address translation traversal service
  19. * @author Christian Grothoff
  20. *
  21. * The purpose of this service is to enable transports to
  22. * traverse NAT routers, by providing traversal options and
  23. * knowledge about the local network topology.
  24. *
  25. * TODO:
  26. * - migrate test cases to new NAT service
  27. * - add new traceroute-based logic for external IP detection
  28. *
  29. * - implement & test STUN processing to classify NAT;
  30. * basically, open port & try different methods.
  31. */
  32. #include "platform.h"
  33. #include <math.h>
  34. #include "gnunet_util_lib.h"
  35. #include "gnunet_protocols.h"
  36. #include "gnunet_signatures.h"
  37. #include "gnunet_statistics_service.h"
  38. #include "gnunet_resolver_service.h"
  39. #include "gnunet_nat_service.h"
  40. #include "gnunet-service-nat.h"
  41. #include "gnunet-service-nat_externalip.h"
  42. #include "gnunet-service-nat_stun.h"
  43. #include "gnunet-service-nat_mini.h"
  44. #include "gnunet-service-nat_helper.h"
  45. #include "nat.h"
  46. #include <gcrypt.h>
  47. /**
  48. * How often should we ask the OS about a list of active
  49. * network interfaces?
  50. */
  51. #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
  52. /**
  53. * How long do we wait until we forcefully terminate autoconfiguration?
  54. */
  55. #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
  56. /**
  57. * How often do we scan for changes in how our external (dyndns) hostname resolves?
  58. */
  59. #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
  60. /**
  61. * Information we track per client address.
  62. */
  63. struct ClientAddress
  64. {
  65. /**
  66. * Network address used by the client.
  67. */
  68. struct sockaddr_storage ss;
  69. /**
  70. * Handle to active UPnP request where we asked upnpc to open
  71. * a port at the NAT. NULL if we do not have such a request
  72. * pending.
  73. */
  74. struct GNUNET_NAT_MiniHandle *mh;
  75. };
  76. /**
  77. * List of local addresses this system has.
  78. */
  79. struct LocalAddressList
  80. {
  81. /**
  82. * This is a linked list.
  83. */
  84. struct LocalAddressList *next;
  85. /**
  86. * Previous entry.
  87. */
  88. struct LocalAddressList *prev;
  89. /**
  90. * Context for a gnunet-helper-nat-server used to listen
  91. * for ICMP messages to this client for connection reversal.
  92. */
  93. struct HelperContext *hc;
  94. /**
  95. * The address itself (i.e. `struct sockaddr_in` or `struct
  96. * sockaddr_in6`, in the respective byte order).
  97. */
  98. struct sockaddr_storage addr;
  99. /**
  100. * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
  101. */
  102. int af;
  103. /**
  104. * #GNUNET_YES if we saw this one in the previous iteration,
  105. * but not in the current iteration and thus might need to
  106. * remove it at the end.
  107. */
  108. int old;
  109. /**
  110. * What type of address is this?
  111. */
  112. enum GNUNET_NAT_AddressClass ac;
  113. };
  114. /**
  115. * Internal data structure we track for each of our clients.
  116. */
  117. struct ClientHandle
  118. {
  119. /**
  120. * Kept in a DLL.
  121. */
  122. struct ClientHandle *next;
  123. /**
  124. * Kept in a DLL.
  125. */
  126. struct ClientHandle *prev;
  127. /**
  128. * Underlying handle for this client with the service.
  129. */
  130. struct GNUNET_SERVICE_Client *client;
  131. /**
  132. * Message queue for communicating with the client.
  133. */
  134. struct GNUNET_MQ_Handle *mq;
  135. /**
  136. * Array of addresses used by the service.
  137. */
  138. struct ClientAddress *caddrs;
  139. /**
  140. * External DNS name and port given by user due to manual
  141. * hole punching. Special DNS name 'AUTO' is used to indicate
  142. * desire for automatic determination of the external IP
  143. * (instead of DNS or manual configuration, i.e. to be used
  144. * if the IP keeps changing and we have no DynDNS, but we do
  145. * have a hole punched).
  146. */
  147. char *hole_external;
  148. /**
  149. * Name of the configuration section this client cares about.
  150. */
  151. char *section_name;
  152. /**
  153. * Task for periodically re-running the @e ext_dns DNS lookup.
  154. */
  155. struct GNUNET_SCHEDULER_Task *ext_dns_task;
  156. /**
  157. * Handle for (DYN)DNS lookup of our external IP as given in
  158. * @e hole_external.
  159. */
  160. struct GNUNET_RESOLVER_RequestHandle *ext_dns;
  161. /**
  162. * Handle for monitoring external IP changes.
  163. */
  164. struct GN_ExternalIPMonitor *external_monitor;
  165. /**
  166. * DLL of external IP addresses as given in @e hole_external.
  167. */
  168. struct LocalAddressList *ext_addr_head;
  169. /**
  170. * DLL of external IP addresses as given in @e hole_external.
  171. */
  172. struct LocalAddressList *ext_addr_tail;
  173. /**
  174. * Port number we found in @e hole_external.
  175. */
  176. uint16_t ext_dns_port;
  177. /**
  178. * What does this client care about?
  179. */
  180. enum GNUNET_NAT_RegisterFlags flags;
  181. /**
  182. * Is any of the @e caddrs in a reserved subnet for NAT?
  183. */
  184. int natted_address;
  185. /**
  186. * Number of addresses that this service is bound to.
  187. * Length of the @e caddrs array.
  188. */
  189. uint16_t num_caddrs;
  190. /**
  191. * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
  192. */
  193. uint8_t proto;
  194. };
  195. /**
  196. * External IP address as given to us via some STUN server.
  197. */
  198. struct StunExternalIP
  199. {
  200. /**
  201. * Kept in a DLL.
  202. */
  203. struct StunExternalIP *next;
  204. /**
  205. * Kept in a DLL.
  206. */
  207. struct StunExternalIP *prev;
  208. /**
  209. * Task we run to remove this entry when it is stale.
  210. */
  211. struct GNUNET_SCHEDULER_Task *timeout_task;
  212. /**
  213. * Our external IP address as reported by the
  214. * STUN server.
  215. */
  216. struct sockaddr_in external_addr;
  217. /**
  218. * Address of the reporting STUN server. Used to
  219. * detect when a STUN server changes its opinion
  220. * to more quickly remove stale results.
  221. */
  222. struct sockaddr_storage stun_server_addr;
  223. /**
  224. * Number of bytes used in @e stun_server_addr.
  225. */
  226. size_t stun_server_addr_len;
  227. };
  228. /**
  229. * Timeout to use when STUN data is considered stale.
  230. */
  231. static struct GNUNET_TIME_Relative stun_stale_timeout;
  232. /**
  233. * How often do we scan for changes in how our external (dyndns) hostname resolves?
  234. */
  235. static struct GNUNET_TIME_Relative dyndns_frequency;
  236. /**
  237. * Handle to our current configuration.
  238. */
  239. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  240. /**
  241. * Handle to the statistics service.
  242. */
  243. static struct GNUNET_STATISTICS_Handle *stats;
  244. /**
  245. * Task scheduled to periodically scan our network interfaces.
  246. */
  247. static struct GNUNET_SCHEDULER_Task *scan_task;
  248. /**
  249. * Head of client DLL.
  250. */
  251. static struct ClientHandle *ch_head;
  252. /**
  253. * Tail of client DLL.
  254. */
  255. static struct ClientHandle *ch_tail;
  256. /**
  257. * Head of DLL of local addresses.
  258. */
  259. static struct LocalAddressList *lal_head;
  260. /**
  261. * Tail of DLL of local addresses.
  262. */
  263. static struct LocalAddressList *lal_tail;
  264. /**
  265. * Kept in a DLL.
  266. */
  267. static struct StunExternalIP *se_head;
  268. /**
  269. * Kept in a DLL.
  270. */
  271. static struct StunExternalIP *se_tail;
  272. /**
  273. * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
  274. * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
  275. */
  276. int enable_upnp;
  277. /**
  278. * Remove and free an entry from the #lal_head DLL.
  279. *
  280. * @param lal entry to free
  281. */
  282. static void
  283. free_lal (struct LocalAddressList *lal)
  284. {
  285. GNUNET_CONTAINER_DLL_remove (lal_head,
  286. lal_tail,
  287. lal);
  288. if (NULL != lal->hc)
  289. {
  290. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  291. "Lost NATed local address %s, stopping NAT server\n",
  292. GNUNET_a2s ((const struct sockaddr *) &lal->addr,
  293. sizeof (struct sockaddr_in)));
  294. GN_stop_gnunet_nat_server_ (lal->hc);
  295. lal->hc = NULL;
  296. }
  297. GNUNET_free (lal);
  298. }
  299. /**
  300. * Free the DLL starting at #lal_head.
  301. */
  302. static void
  303. destroy_lal ()
  304. {
  305. struct LocalAddressList *lal;
  306. while (NULL != (lal = lal_head))
  307. free_lal (lal);
  308. }
  309. /**
  310. * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
  311. * client.
  312. *
  313. * @param cls client who sent the message
  314. * @param message the message received
  315. * @return #GNUNET_OK if message is well-formed
  316. */
  317. static int
  318. check_register (void *cls,
  319. const struct GNUNET_NAT_RegisterMessage *message)
  320. {
  321. uint16_t num_addrs = ntohs (message->num_addrs);
  322. const char *off = (const char *) &message[1];
  323. size_t left = ntohs (message->header.size) - sizeof (*message);
  324. for (unsigned int i=0;i<num_addrs;i++)
  325. {
  326. size_t alen;
  327. const struct sockaddr *sa = (const struct sockaddr *) off;
  328. if (sizeof (sa_family_t) > left)
  329. {
  330. GNUNET_break (0);
  331. return GNUNET_SYSERR;
  332. }
  333. switch (sa->sa_family)
  334. {
  335. case AF_INET:
  336. alen = sizeof (struct sockaddr_in);
  337. break;
  338. case AF_INET6:
  339. alen = sizeof (struct sockaddr_in6);
  340. break;
  341. #if AF_UNIX
  342. case AF_UNIX:
  343. alen = sizeof (struct sockaddr_un);
  344. break;
  345. #endif
  346. default:
  347. GNUNET_break (0);
  348. return GNUNET_SYSERR;
  349. }
  350. if (alen > left)
  351. {
  352. GNUNET_break (0);
  353. return GNUNET_SYSERR;
  354. }
  355. off += alen;
  356. left -= alen;
  357. }
  358. if (left != ntohs (message->str_len))
  359. {
  360. GNUNET_break (0);
  361. return GNUNET_SYSERR;
  362. }
  363. return GNUNET_OK;
  364. }
  365. /**
  366. * Check if @a ip is in @a network with @a bits netmask.
  367. *
  368. * @param network to test
  369. * @param ip IP address to test
  370. * @param bits bitmask for the network
  371. * @return #GNUNET_YES if @a ip is in @a network
  372. */
  373. static int
  374. match_ipv4 (const char *network,
  375. const struct in_addr *ip,
  376. uint8_t bits)
  377. {
  378. struct in_addr net;
  379. if (0 == ip->s_addr)
  380. return GNUNET_YES;
  381. if (0 == bits)
  382. return GNUNET_YES;
  383. GNUNET_assert (1 == inet_pton (AF_INET,
  384. network,
  385. &net));
  386. return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
  387. }
  388. /**
  389. * Check if @a ip is in @a network with @a bits netmask.
  390. *
  391. * @param network to test
  392. * @param ip IP address to test
  393. * @param bits bitmask for the network
  394. * @return #GNUNET_YES if @a ip is in @a network
  395. */
  396. static int
  397. match_ipv6 (const char *network,
  398. const struct in6_addr *ip,
  399. uint8_t bits)
  400. {
  401. struct in6_addr net;
  402. struct in6_addr mask;
  403. unsigned int off;
  404. if (0 == bits)
  405. return GNUNET_YES;
  406. GNUNET_assert (1 == inet_pton (AF_INET6,
  407. network,
  408. &net));
  409. memset (&mask, 0, sizeof (mask));
  410. if (0 == memcmp (&mask,
  411. ip,
  412. sizeof (mask)))
  413. return GNUNET_YES;
  414. off = 0;
  415. while (bits > 8)
  416. {
  417. mask.s6_addr[off++] = 0xFF;
  418. bits -= 8;
  419. }
  420. while (bits > 0)
  421. {
  422. mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
  423. bits--;
  424. }
  425. for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
  426. if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
  427. (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
  428. return GNUNET_NO;
  429. return GNUNET_YES;
  430. }
  431. /**
  432. * Test if the given IPv4 address is in a known range
  433. * for private networks.
  434. *
  435. * @param ip address to test
  436. * @return #GNUNET_YES if @a ip is in a NAT range
  437. */
  438. static int
  439. is_nat_v4 (const struct in_addr *ip)
  440. {
  441. return
  442. match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
  443. match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
  444. match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
  445. match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
  446. match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
  447. }
  448. /**
  449. * Test if the given IPv6 address is in a known range
  450. * for private networks.
  451. *
  452. * @param ip address to test
  453. * @return #GNUNET_YES if @a ip is in a NAT range
  454. */
  455. static int
  456. is_nat_v6 (const struct in6_addr *ip)
  457. {
  458. return
  459. match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
  460. match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
  461. match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
  462. }
  463. /**
  464. * Closure for #ifc_proc.
  465. */
  466. struct IfcProcContext
  467. {
  468. /**
  469. * Head of DLL of local addresses.
  470. */
  471. struct LocalAddressList *lal_head;
  472. /**
  473. * Tail of DLL of local addresses.
  474. */
  475. struct LocalAddressList *lal_tail;
  476. };
  477. /**
  478. * Callback function invoked for each interface found. Adds them
  479. * to our new address list.
  480. *
  481. * @param cls a `struct IfcProcContext *`
  482. * @param name name of the interface (can be NULL for unknown)
  483. * @param isDefault is this presumably the default interface
  484. * @param addr address of this interface (can be NULL for unknown or unassigned)
  485. * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
  486. * @param netmask the network mask (can be NULL for unknown or unassigned)
  487. * @param addrlen length of the address
  488. * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
  489. */
  490. static int
  491. ifc_proc (void *cls,
  492. const char *name,
  493. int isDefault,
  494. const struct sockaddr *addr,
  495. const struct sockaddr *broadcast_addr,
  496. const struct sockaddr *netmask,
  497. socklen_t addrlen)
  498. {
  499. struct IfcProcContext *ifc_ctx = cls;
  500. struct LocalAddressList *lal;
  501. size_t alen;
  502. const struct in_addr *ip4;
  503. const struct in6_addr *ip6;
  504. enum GNUNET_NAT_AddressClass ac;
  505. switch (addr->sa_family)
  506. {
  507. case AF_INET:
  508. alen = sizeof (struct sockaddr_in);
  509. ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
  510. if (match_ipv4 ("127.0.0.0", ip4, 8))
  511. ac = GNUNET_NAT_AC_LOOPBACK;
  512. else if (is_nat_v4 (ip4))
  513. ac = GNUNET_NAT_AC_LAN;
  514. else
  515. ac = GNUNET_NAT_AC_GLOBAL;
  516. break;
  517. case AF_INET6:
  518. alen = sizeof (struct sockaddr_in6);
  519. ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
  520. if (match_ipv6 ("::1", ip6, 128))
  521. ac = GNUNET_NAT_AC_LOOPBACK;
  522. else if (is_nat_v6 (ip6))
  523. ac = GNUNET_NAT_AC_LAN;
  524. else
  525. ac = GNUNET_NAT_AC_GLOBAL;
  526. if ( (ip6->s6_addr[11] == 0xFF) &&
  527. (ip6->s6_addr[12] == 0xFE) )
  528. {
  529. /* contains a MAC, be extra careful! */
  530. ac |= GNUNET_NAT_AC_PRIVATE;
  531. }
  532. break;
  533. #if AF_UNIX
  534. case AF_UNIX:
  535. GNUNET_break (0);
  536. return GNUNET_OK;
  537. #endif
  538. default:
  539. GNUNET_break (0);
  540. return GNUNET_OK;
  541. }
  542. lal = GNUNET_malloc (sizeof (*lal));
  543. lal->af = addr->sa_family;
  544. lal->ac = ac;
  545. GNUNET_memcpy (&lal->addr,
  546. addr,
  547. alen);
  548. GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
  549. ifc_ctx->lal_tail,
  550. lal);
  551. return GNUNET_OK;
  552. }
  553. /**
  554. * Notify client about a change in the list of addresses this peer
  555. * has.
  556. *
  557. * @param ac address class of the entry in the list that changed
  558. * @param ch client to contact
  559. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  560. * @param addr the address that changed
  561. * @param addr_len number of bytes in @a addr
  562. */
  563. static void
  564. notify_client (enum GNUNET_NAT_AddressClass ac,
  565. struct ClientHandle *ch,
  566. int add,
  567. const void *addr,
  568. size_t addr_len)
  569. {
  570. struct GNUNET_MQ_Envelope *env;
  571. struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
  572. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  573. "Notifying client about %s of IP %s\n",
  574. add ? "addition" : "removal",
  575. GNUNET_a2s (addr,
  576. addr_len));
  577. env = GNUNET_MQ_msg_extra (msg,
  578. addr_len,
  579. GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
  580. msg->add_remove = htonl (add);
  581. msg->addr_class = htonl (ac);
  582. GNUNET_memcpy (&msg[1],
  583. addr,
  584. addr_len);
  585. GNUNET_MQ_send (ch->mq,
  586. env);
  587. }
  588. /**
  589. * Check if we should bother to notify this client about this
  590. * address change, and if so, do it.
  591. *
  592. * @param delta the entry in the list that changed
  593. * @param ch client to check
  594. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  595. */
  596. static void
  597. check_notify_client (struct LocalAddressList *delta,
  598. struct ClientHandle *ch,
  599. int add)
  600. {
  601. size_t alen;
  602. struct sockaddr_in v4;
  603. struct sockaddr_in6 v6;
  604. if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
  605. {
  606. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  607. "Not notifying client as it does not care about addresses\n");
  608. return;
  609. }
  610. switch (delta->af)
  611. {
  612. case AF_INET:
  613. alen = sizeof (struct sockaddr_in);
  614. GNUNET_memcpy (&v4,
  615. &delta->addr,
  616. alen);
  617. /* Check for client notifications */
  618. for (unsigned int i=0;i<ch->num_caddrs;i++)
  619. {
  620. const struct sockaddr_in *c4;
  621. if (AF_INET != ch->caddrs[i].ss.ss_family)
  622. continue; /* IPv4 not relevant */
  623. c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
  624. if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
  625. (0 != c4->sin_addr.s_addr) &&
  626. (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
  627. continue; /* bound to loopback, but this is not loopback */
  628. if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
  629. match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
  630. continue; /* bound to non-loopback, but this is loopback */
  631. if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
  632. (0 != c4->sin_addr.s_addr) &&
  633. (! is_nat_v4 (&v4.sin_addr)) )
  634. continue; /* based on external-IP, but this IP is not
  635. from private address range. */
  636. if ( (0 != memcmp (&v4.sin_addr,
  637. &c4->sin_addr,
  638. sizeof (struct in_addr))) &&
  639. (0 != c4->sin_addr.s_addr) &&
  640. (! is_nat_v4 (&c4->sin_addr)) )
  641. continue; /* this IP is not from private address range,
  642. and IP does not match. */
  643. /* OK, IP seems relevant, notify client */
  644. if (0 == htons (v4.sin_port))
  645. v4.sin_port = c4->sin_port;
  646. notify_client (delta->ac,
  647. ch,
  648. add,
  649. &v4,
  650. alen);
  651. }
  652. break;
  653. case AF_INET6:
  654. alen = sizeof (struct sockaddr_in6);
  655. GNUNET_memcpy (&v6,
  656. &delta->addr,
  657. alen);
  658. for (unsigned int i=0;i<ch->num_caddrs;i++)
  659. {
  660. const struct sockaddr_in6 *c6;
  661. if (AF_INET6 != ch->caddrs[i].ss.ss_family)
  662. continue; /* IPv4 not relevant */
  663. c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
  664. if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
  665. (0 != memcmp (&c6->sin6_addr,
  666. &in6addr_any,
  667. sizeof (struct in6_addr))) &&
  668. (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
  669. continue; /* bound to loopback, but this is not loopback */
  670. if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
  671. match_ipv6 ("::1", &v6.sin6_addr, 128) )
  672. continue; /* bound to non-loopback, but this is loopback */
  673. if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
  674. (0 != memcmp (&c6->sin6_addr,
  675. &in6addr_any,
  676. sizeof (struct in6_addr))) &&
  677. (! is_nat_v6 (&v6.sin6_addr)) )
  678. continue; /* based on external-IP, but this IP is not
  679. from private address range. */
  680. if ( (0 != memcmp (&v6.sin6_addr,
  681. &c6->sin6_addr,
  682. sizeof (struct in6_addr))) &&
  683. (0 != memcmp (&c6->sin6_addr,
  684. &in6addr_any,
  685. sizeof (struct in6_addr))) &&
  686. (! is_nat_v6 (&c6->sin6_addr)) )
  687. continue; /* this IP is not from private address range,
  688. and IP does not match. */
  689. if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
  690. (0 != memcmp (&c6->sin6_addr,
  691. &in6addr_any,
  692. sizeof (struct in6_addr))) &&
  693. (0 != memcmp (&v6.sin6_addr,
  694. &c6->sin6_addr,
  695. sizeof (struct in6_addr))) &&
  696. (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
  697. continue; /* client bound to link-local, and the other address
  698. does not match and is not an external IP */
  699. /* OK, IP seems relevant, notify client */
  700. if (0 == htons (v6.sin6_port))
  701. v6.sin6_port = c6->sin6_port;
  702. notify_client (delta->ac,
  703. ch,
  704. add,
  705. &v6,
  706. alen);
  707. }
  708. break;
  709. default:
  710. GNUNET_break (0);
  711. return;
  712. }
  713. }
  714. /**
  715. * Notify all clients about a change in the list
  716. * of addresses this peer has.
  717. *
  718. * @param delta the entry in the list that changed
  719. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  720. */
  721. static void
  722. notify_clients (struct LocalAddressList *delta,
  723. int add)
  724. {
  725. for (struct ClientHandle *ch = ch_head;
  726. NULL != ch;
  727. ch = ch->next)
  728. check_notify_client (delta,
  729. ch,
  730. add);
  731. }
  732. /**
  733. * Tell relevant client about a change in our external
  734. * IPv4 address.
  735. *
  736. * @param cls client to check if it cares and possibly notify
  737. * @param v4 the external address that changed
  738. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  739. */
  740. static void
  741. notify_client_external_ipv4_change (void *cls,
  742. const struct in_addr *v4,
  743. int add)
  744. {
  745. struct ClientHandle *ch = cls;
  746. struct sockaddr_in sa;
  747. int have_v4;
  748. /* (0) check if this impacts 'hole_external' */
  749. if ( (NULL != ch->hole_external) &&
  750. (0 == strcasecmp (ch->hole_external,
  751. "AUTO")) )
  752. {
  753. struct LocalAddressList lal;
  754. struct sockaddr_in *s4;
  755. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  756. "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
  757. (unsigned int) ch->ext_dns_port,
  758. ch->section_name);
  759. memset (&lal, 0, sizeof (lal));
  760. s4 = (struct sockaddr_in *) &lal.addr;
  761. s4->sin_family = AF_INET;
  762. s4->sin_port = htons (ch->ext_dns_port);
  763. s4->sin_addr = *v4;
  764. lal.af = AF_INET;
  765. lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
  766. check_notify_client (&lal,
  767. ch,
  768. add);
  769. }
  770. /* (1) check if client cares. */
  771. if (! ch->natted_address)
  772. return;
  773. have_v4 = GNUNET_NO;
  774. for (unsigned int i=0;i<ch->num_caddrs;i++)
  775. {
  776. const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
  777. if (AF_INET != ss->ss_family)
  778. continue;
  779. have_v4 = GNUNET_YES;
  780. break;
  781. }
  782. if (GNUNET_NO == have_v4)
  783. return; /* IPv6-only */
  784. /* (2) build address info */
  785. memset (&sa,
  786. 0,
  787. sizeof (sa));
  788. sa.sin_family = AF_INET;
  789. sa.sin_addr = *v4;
  790. sa.sin_port = htons (0);
  791. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  792. "Detected eternal IP %s, notifying client of external IP (without port)\n",
  793. GNUNET_a2s ((const struct sockaddr *) &sa,
  794. sizeof (sa)));
  795. /* (3) notify client of change */
  796. notify_client (is_nat_v4 (v4)
  797. ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
  798. : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
  799. ch,
  800. add,
  801. &sa,
  802. sizeof (sa));
  803. }
  804. /**
  805. * We got a connection reversal request from another peer.
  806. * Notify applicable clients.
  807. *
  808. * @param cls closure with the `struct LocalAddressList`
  809. * @param ra IP address of the peer who wants us to connect to it
  810. */
  811. static void
  812. reversal_callback (void *cls,
  813. const struct sockaddr_in *ra)
  814. {
  815. struct LocalAddressList *lal = cls;
  816. const struct sockaddr_in *l4;
  817. GNUNET_assert (AF_INET == lal->af);
  818. l4 = (const struct sockaddr_in *) &lal->addr;
  819. for (struct ClientHandle *ch = ch_head;
  820. NULL != ch;
  821. ch = ch->next)
  822. {
  823. struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
  824. struct GNUNET_MQ_Envelope *env;
  825. int match;
  826. /* Check if client is in applicable range for ICMP NAT traversal
  827. for this local address */
  828. if (! ch->natted_address)
  829. continue;
  830. match = GNUNET_NO;
  831. for (unsigned int i=0;i<ch->num_caddrs;i++)
  832. {
  833. struct ClientAddress *ca = &ch->caddrs[i];
  834. const struct sockaddr_in *c4;
  835. if (AF_INET != ca->ss.ss_family)
  836. continue;
  837. c4 = (const struct sockaddr_in *) &ca->ss;
  838. if ( (0 != c4->sin_addr.s_addr) &&
  839. (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
  840. continue;
  841. match = GNUNET_YES;
  842. break;
  843. }
  844. if (! match)
  845. continue;
  846. /* Notify applicable client about connection reversal request */
  847. env = GNUNET_MQ_msg_extra (crrm,
  848. sizeof (struct sockaddr_in),
  849. GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
  850. GNUNET_memcpy (&crrm[1],
  851. ra,
  852. sizeof (struct sockaddr_in));
  853. GNUNET_MQ_send (ch->mq,
  854. env);
  855. }
  856. }
  857. /**
  858. * Task we run periodically to scan for network interfaces.
  859. *
  860. * @param cls NULL
  861. */
  862. static void
  863. run_scan (void *cls)
  864. {
  865. struct IfcProcContext ifc_ctx;
  866. int found;
  867. int have_nat;
  868. struct LocalAddressList *lnext;
  869. scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
  870. &run_scan,
  871. NULL);
  872. memset (&ifc_ctx,
  873. 0,
  874. sizeof (ifc_ctx));
  875. GNUNET_OS_network_interfaces_list (&ifc_proc,
  876. &ifc_ctx);
  877. /* remove addresses that disappeared */
  878. for (struct LocalAddressList *lal = lal_head;
  879. NULL != lal;
  880. lal = lnext)
  881. {
  882. lnext = lal->next;
  883. found = GNUNET_NO;
  884. for (struct LocalAddressList *pos = ifc_ctx.lal_head;
  885. NULL != pos;
  886. pos = pos->next)
  887. {
  888. if ( (pos->af == lal->af) &&
  889. (0 == memcmp (&lal->addr,
  890. &pos->addr,
  891. (AF_INET == lal->af)
  892. ? sizeof (struct sockaddr_in)
  893. : sizeof (struct sockaddr_in6))) )
  894. {
  895. found = GNUNET_YES;
  896. }
  897. }
  898. if (GNUNET_NO == found)
  899. {
  900. notify_clients (lal,
  901. GNUNET_NO);
  902. free_lal (lal);
  903. }
  904. }
  905. /* add addresses that appeared */
  906. have_nat = GNUNET_NO;
  907. for (struct LocalAddressList *pos = ifc_ctx.lal_head;
  908. NULL != pos;
  909. pos = ifc_ctx.lal_head)
  910. {
  911. found = GNUNET_NO;
  912. if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
  913. have_nat = GNUNET_YES;
  914. for (struct LocalAddressList *lal = lal_head;
  915. NULL != lal;
  916. lal = lal->next)
  917. {
  918. if ( (pos->af == lal->af) &&
  919. (0 == memcmp (&lal->addr,
  920. &pos->addr,
  921. (AF_INET == lal->af)
  922. ? sizeof (struct sockaddr_in)
  923. : sizeof (struct sockaddr_in6))) )
  924. found = GNUNET_YES;
  925. }
  926. GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
  927. ifc_ctx.lal_tail,
  928. pos);
  929. if (GNUNET_YES == found)
  930. {
  931. GNUNET_free (pos);
  932. }
  933. else
  934. {
  935. notify_clients (pos,
  936. GNUNET_YES);
  937. GNUNET_CONTAINER_DLL_insert (lal_head,
  938. lal_tail,
  939. pos);
  940. if ( (AF_INET == pos->af) &&
  941. (NULL == pos->hc) &&
  942. (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
  943. {
  944. const struct sockaddr_in *s4
  945. = (const struct sockaddr_in *) &pos->addr;
  946. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  947. "Found NATed local address %s, starting NAT server\n",
  948. GNUNET_a2s ((const struct sockaddr *) &pos->addr,
  949. sizeof (*s4)));
  950. pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
  951. &reversal_callback,
  952. pos);
  953. }
  954. }
  955. }
  956. GN_nat_status_changed (have_nat);
  957. }
  958. /**
  959. * Function called whenever our set of external addresses
  960. * as created by `upnpc` changes.
  961. *
  962. * @param cls closure with our `struct ClientHandle *`
  963. * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
  964. * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
  965. * @param addr either the previous or the new public IP address
  966. * @param addrlen actual length of the @a addr
  967. * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
  968. */
  969. static void
  970. upnp_addr_change_cb (void *cls,
  971. int add_remove,
  972. const struct sockaddr *addr,
  973. socklen_t addrlen,
  974. enum GNUNET_NAT_StatusCode result)
  975. {
  976. struct ClientHandle *ch = cls;
  977. enum GNUNET_NAT_AddressClass ac;
  978. switch (result)
  979. {
  980. case GNUNET_NAT_ERROR_SUCCESS:
  981. GNUNET_assert (NULL != addr);
  982. break;
  983. case GNUNET_NAT_ERROR_UPNPC_FAILED:
  984. case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
  985. case GNUNET_NAT_ERROR_IPC_FAILURE:
  986. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  987. "Running upnpc failed: %d\n",
  988. result);
  989. return;
  990. case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
  991. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  992. "external-ip binary not found\n");
  993. return;
  994. case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
  995. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  996. "upnpc binary not found\n");
  997. return;
  998. case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
  999. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1000. "external-ip binary could not be run\n");
  1001. return;
  1002. case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
  1003. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1004. "upnpc failed to create port mapping\n");
  1005. return;
  1006. case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
  1007. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1008. "Invalid output from upnpc\n");
  1009. return;
  1010. case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
  1011. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1012. "Invalid address returned by upnpc\n");
  1013. return;
  1014. default:
  1015. GNUNET_break (0); /* should not be possible */
  1016. return;
  1017. }
  1018. switch (addr->sa_family)
  1019. {
  1020. case AF_INET:
  1021. ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
  1022. ? GNUNET_NAT_AC_LAN
  1023. : GNUNET_NAT_AC_EXTERN;
  1024. break;
  1025. case AF_INET6:
  1026. ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
  1027. ? GNUNET_NAT_AC_LAN
  1028. : GNUNET_NAT_AC_EXTERN;
  1029. break;
  1030. default:
  1031. GNUNET_break (0);
  1032. return;
  1033. }
  1034. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1035. "upnp external address %s: %s\n",
  1036. add_remove ? "added" : "removed",
  1037. GNUNET_a2s (addr,
  1038. addrlen));
  1039. notify_client (ac,
  1040. ch,
  1041. add_remove,
  1042. addr,
  1043. addrlen);
  1044. }
  1045. /**
  1046. * Resolve the `hole_external` name to figure out our
  1047. * external address from a manually punched hole. The
  1048. * port number has already been parsed, this task is
  1049. * responsible for periodically doing a DNS lookup.
  1050. *
  1051. * @param ch client handle to act upon
  1052. */
  1053. static void
  1054. dyndns_lookup (void *cls);
  1055. /**
  1056. * Our (external) hostname was resolved. Update lists of
  1057. * current external IPs (note that DNS may return multiple
  1058. * addresses!) and notify client accordingly.
  1059. *
  1060. * @param cls the `struct ClientHandle`
  1061. * @param addr NULL on error, otherwise result of DNS lookup
  1062. * @param addrlen number of bytes in @a addr
  1063. */
  1064. static void
  1065. process_external_ip (void *cls,
  1066. const struct sockaddr *addr,
  1067. socklen_t addrlen)
  1068. {
  1069. struct ClientHandle *ch = cls;
  1070. struct LocalAddressList *lal;
  1071. struct sockaddr_storage ss;
  1072. struct sockaddr_in *v4;
  1073. struct sockaddr_in6 *v6;
  1074. if (NULL == addr)
  1075. {
  1076. struct LocalAddressList *laln;
  1077. ch->ext_dns = NULL;
  1078. ch->ext_dns_task
  1079. = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
  1080. &dyndns_lookup,
  1081. ch);
  1082. /* Current iteration is over, remove 'old' IPs now */
  1083. for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
  1084. {
  1085. laln = lal->next;
  1086. if (GNUNET_YES == lal->old)
  1087. {
  1088. GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
  1089. ch->ext_addr_tail,
  1090. lal);
  1091. check_notify_client (lal,
  1092. ch,
  1093. GNUNET_NO);
  1094. GNUNET_free (lal);
  1095. }
  1096. }
  1097. return;
  1098. }
  1099. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1100. "Got IP `%s' for external address `%s'\n",
  1101. GNUNET_a2s (addr,
  1102. addrlen),
  1103. ch->hole_external);
  1104. /* build sockaddr storage with port number */
  1105. memset (&ss,
  1106. 0,
  1107. sizeof (ss));
  1108. GNUNET_memcpy (&ss,
  1109. addr,
  1110. addrlen);
  1111. switch (addr->sa_family)
  1112. {
  1113. case AF_INET:
  1114. v4 = (struct sockaddr_in *) &ss;
  1115. v4->sin_port = htons (ch->ext_dns_port);
  1116. break;
  1117. case AF_INET6:
  1118. v6 = (struct sockaddr_in6 *) &ss;
  1119. v6->sin6_port = htons (ch->ext_dns_port);
  1120. break;
  1121. default:
  1122. GNUNET_break (0);
  1123. return;
  1124. }
  1125. /* See if 'ss' matches any of our known addresses */
  1126. for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
  1127. {
  1128. if (GNUNET_NO == lal->old)
  1129. continue; /* already processed, skip */
  1130. if ( (addr->sa_family == lal->addr.ss_family) &&
  1131. (0 == memcmp (&ss,
  1132. &lal->addr,
  1133. addrlen)) )
  1134. {
  1135. /* Address unchanged, remember so we do not remove */
  1136. lal->old = GNUNET_NO;
  1137. return; /* done here */
  1138. }
  1139. }
  1140. /* notify client, and remember IP for later removal! */
  1141. lal = GNUNET_new (struct LocalAddressList);
  1142. lal->addr = ss;
  1143. lal->af = ss.ss_family;
  1144. lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
  1145. GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
  1146. ch->ext_addr_tail,
  1147. lal);
  1148. check_notify_client (lal,
  1149. ch,
  1150. GNUNET_YES);
  1151. }
  1152. /**
  1153. * Resolve the `hole_external` name to figure out our
  1154. * external address from a manually punched hole. The
  1155. * port number has already been parsed, this task is
  1156. * responsible for periodically doing a DNS lookup.
  1157. *
  1158. * @param ch client handle to act upon
  1159. */
  1160. static void
  1161. dyndns_lookup (void *cls)
  1162. {
  1163. struct ClientHandle *ch = cls;
  1164. struct LocalAddressList *lal;
  1165. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1166. "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
  1167. ch->section_name,
  1168. ch->hole_external,
  1169. (unsigned int) ch->ext_dns_port);
  1170. for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
  1171. lal->old = GNUNET_YES;
  1172. ch->ext_dns_task = NULL;
  1173. ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
  1174. AF_UNSPEC,
  1175. GNUNET_TIME_UNIT_MINUTES,
  1176. &process_external_ip,
  1177. ch);
  1178. }
  1179. /**
  1180. * Resolve the `hole_external` name to figure out our
  1181. * external address from a manually punched hole. The
  1182. * given name may be "AUTO" in which case we should use
  1183. * the IP address(es) we have from upnpc or other methods.
  1184. * The name can also be an IP address, in which case we
  1185. * do not need to do DNS resolution. Finally, we also
  1186. * need to parse the port number.
  1187. *
  1188. * @param ch client handle to act upon
  1189. */
  1190. static void
  1191. lookup_hole_external (struct ClientHandle *ch)
  1192. {
  1193. char *port;
  1194. unsigned int pnum;
  1195. struct sockaddr_in *s4;
  1196. struct LocalAddressList *lal;
  1197. port = strrchr (ch->hole_external, ':');
  1198. if (NULL == port)
  1199. {
  1200. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1201. _("Malformed punched hole specification `%s' (lacks port)\n"),
  1202. ch->hole_external);
  1203. return;
  1204. }
  1205. if ( (1 != sscanf (port + 1,
  1206. "%u",
  1207. &pnum)) ||
  1208. (pnum > 65535) )
  1209. {
  1210. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1211. _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
  1212. port + 1);
  1213. return;
  1214. }
  1215. ch->ext_dns_port = (uint16_t) pnum;
  1216. *port = '\0';
  1217. lal = GNUNET_new (struct LocalAddressList);
  1218. if ('[' == *ch->hole_external)
  1219. {
  1220. struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
  1221. s6->sin6_family = AF_INET6;
  1222. if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
  1223. {
  1224. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1225. _("Malformed punched hole specification `%s' (lacks `]')\n"),
  1226. ch->hole_external);
  1227. GNUNET_free (lal);
  1228. return;
  1229. }
  1230. ch->hole_external[strlen(ch->hole_external)-1] = '\0';
  1231. if (1 != inet_pton (AF_INET6,
  1232. ch->hole_external + 1,
  1233. &s6->sin6_addr))
  1234. {
  1235. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1236. _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
  1237. ch->hole_external + 1);
  1238. GNUNET_free (lal);
  1239. return;
  1240. }
  1241. s6->sin6_port = htons (ch->ext_dns_port);
  1242. lal->af = AF_INET6;
  1243. lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
  1244. GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
  1245. ch->ext_addr_tail,
  1246. lal);
  1247. check_notify_client (lal,
  1248. ch,
  1249. GNUNET_YES);
  1250. return;
  1251. }
  1252. s4 = (struct sockaddr_in *) &lal->addr;
  1253. s4->sin_family = AF_INET;
  1254. if (1 == inet_pton (AF_INET,
  1255. ch->hole_external,
  1256. &s4->sin_addr))
  1257. {
  1258. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1259. "IPv4 punched hole given for `%s' via `%s:%u'\n",
  1260. ch->section_name,
  1261. ch->hole_external,
  1262. (unsigned int) ch->ext_dns_port);
  1263. s4->sin_port = htons (ch->ext_dns_port);
  1264. lal->af = AF_INET;
  1265. lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
  1266. GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
  1267. ch->ext_addr_tail,
  1268. lal);
  1269. check_notify_client (lal,
  1270. ch,
  1271. GNUNET_YES);
  1272. return;
  1273. }
  1274. if (0 == strcasecmp (ch->hole_external,
  1275. "AUTO"))
  1276. {
  1277. /* handled in #notify_client_external_ipv4_change() */
  1278. GNUNET_free (lal);
  1279. return;
  1280. }
  1281. /* got a DNS name, trigger lookup! */
  1282. GNUNET_free (lal);
  1283. ch->ext_dns_task
  1284. = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
  1285. ch);
  1286. }
  1287. /**
  1288. * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
  1289. * We remember the client for updates upon future NAT events.
  1290. *
  1291. * @param cls client who sent the message
  1292. * @param message the message received
  1293. */
  1294. static void
  1295. handle_register (void *cls,
  1296. const struct GNUNET_NAT_RegisterMessage *message)
  1297. {
  1298. struct ClientHandle *ch = cls;
  1299. const char *off;
  1300. size_t left;
  1301. if ( (0 != ch->proto) ||
  1302. (NULL != ch->caddrs) )
  1303. {
  1304. /* double registration not allowed */
  1305. GNUNET_break (0);
  1306. GNUNET_SERVICE_client_drop (ch->client);
  1307. return;
  1308. }
  1309. ch->flags = message->flags;
  1310. ch->proto = message->proto;
  1311. ch->num_caddrs = ntohs (message->num_addrs);
  1312. ch->caddrs = GNUNET_new_array (ch->num_caddrs,
  1313. struct ClientAddress);
  1314. left = ntohs (message->header.size) - sizeof (*message);
  1315. off = (const char *) &message[1];
  1316. for (unsigned int i=0;i<ch->num_caddrs;i++)
  1317. {
  1318. const struct sockaddr *sa = (const struct sockaddr *) off;
  1319. size_t alen;
  1320. uint16_t port;
  1321. int is_nat;
  1322. if (sizeof (sa_family_t) > left)
  1323. {
  1324. GNUNET_break (0);
  1325. GNUNET_SERVICE_client_drop (ch->client);
  1326. return;
  1327. }
  1328. is_nat = GNUNET_NO;
  1329. switch (sa->sa_family)
  1330. {
  1331. case AF_INET:
  1332. {
  1333. struct sockaddr_in s4;
  1334. GNUNET_memcpy (&s4,
  1335. off,
  1336. sizeof (struct sockaddr_in));
  1337. alen = sizeof (struct sockaddr_in);
  1338. if (is_nat_v4 (&s4.sin_addr))
  1339. is_nat = GNUNET_YES;
  1340. port = ntohs (s4.sin_port);
  1341. }
  1342. break;
  1343. case AF_INET6:
  1344. {
  1345. struct sockaddr_in6 s6;
  1346. GNUNET_memcpy (&s6,
  1347. off,
  1348. sizeof (struct sockaddr_in6));
  1349. alen = sizeof (struct sockaddr_in6);
  1350. if (is_nat_v6 (&s6.sin6_addr))
  1351. is_nat = GNUNET_YES;
  1352. port = ntohs (s6.sin6_port);
  1353. }
  1354. break;
  1355. #if AF_UNIX
  1356. case AF_UNIX:
  1357. alen = sizeof (struct sockaddr_un);
  1358. port = 0;
  1359. break;
  1360. #endif
  1361. default:
  1362. GNUNET_break (0);
  1363. GNUNET_SERVICE_client_drop (ch->client);
  1364. return;
  1365. }
  1366. /* store address */
  1367. GNUNET_assert (alen <= left);
  1368. GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
  1369. GNUNET_memcpy (&ch->caddrs[i].ss,
  1370. off,
  1371. alen);
  1372. /* If applicable, try UPNPC NAT punching */
  1373. if ( (is_nat) &&
  1374. (enable_upnp) &&
  1375. ( (IPPROTO_TCP == ch->proto) ||
  1376. (IPPROTO_UDP == ch->proto) ) )
  1377. {
  1378. ch->natted_address = GNUNET_YES;
  1379. ch->caddrs[i].mh
  1380. = GNUNET_NAT_mini_map_start (port,
  1381. IPPROTO_TCP == ch->proto,
  1382. &upnp_addr_change_cb,
  1383. ch);
  1384. }
  1385. off += alen;
  1386. }
  1387. ch->section_name
  1388. = GNUNET_strndup (off,
  1389. ntohs (message->str_len));
  1390. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1391. "Received REGISTER message from client for subsystem `%s'\n",
  1392. ch->section_name);
  1393. if (GNUNET_OK ==
  1394. GNUNET_CONFIGURATION_get_value_string (cfg,
  1395. ch->section_name,
  1396. "HOLE_EXTERNAL",
  1397. &ch->hole_external))
  1398. lookup_hole_external (ch);
  1399. /* Actually send IP address list to client */
  1400. for (struct LocalAddressList *lal = lal_head;
  1401. NULL != lal;
  1402. lal = lal->next)
  1403. {
  1404. check_notify_client (lal,
  1405. ch,
  1406. GNUNET_YES);
  1407. }
  1408. /* Also consider IPv4 determined by `external-ip` */
  1409. ch->external_monitor
  1410. = GN_external_ipv4_monitor_start (&notify_client_external_ipv4_change,
  1411. ch);
  1412. GNUNET_SERVICE_client_continue (ch->client);
  1413. }
  1414. /**
  1415. * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
  1416. * client.
  1417. *
  1418. * @param cls client who sent the message
  1419. * @param message the message received
  1420. * @return #GNUNET_OK if message is well-formed
  1421. */
  1422. static int
  1423. check_stun (void *cls,
  1424. const struct GNUNET_NAT_HandleStunMessage *message)
  1425. {
  1426. size_t sa_len = ntohs (message->sender_addr_size);
  1427. size_t expect = sa_len + ntohs (message->payload_size);
  1428. if (ntohs (message->header.size) - sizeof (*message) != expect)
  1429. {
  1430. GNUNET_break (0);
  1431. return GNUNET_SYSERR;
  1432. }
  1433. if (sa_len < sizeof (sa_family_t))
  1434. {
  1435. GNUNET_break (0);
  1436. return GNUNET_SYSERR;
  1437. }
  1438. return GNUNET_OK;
  1439. }
  1440. /**
  1441. * Notify all clients about our external IP address
  1442. * as reported by the STUN server.
  1443. *
  1444. * @param ip the external IP
  1445. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  1446. */
  1447. static void
  1448. notify_clients_stun_change (const struct sockaddr_in *ip,
  1449. int add)
  1450. {
  1451. for (struct ClientHandle *ch = ch_head;
  1452. NULL != ch;
  1453. ch = ch->next)
  1454. {
  1455. struct sockaddr_in v4;
  1456. struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
  1457. struct GNUNET_MQ_Envelope *env;
  1458. if (! ch->natted_address)
  1459. continue;
  1460. v4 = *ip;
  1461. v4.sin_port = htons (0);
  1462. env = GNUNET_MQ_msg_extra (msg,
  1463. sizeof (v4),
  1464. GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
  1465. msg->add_remove = htonl ((int32_t) add);
  1466. msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
  1467. GNUNET_NAT_AC_GLOBAL);
  1468. GNUNET_memcpy (&msg[1],
  1469. &v4,
  1470. sizeof (v4));
  1471. GNUNET_MQ_send (ch->mq,
  1472. env);
  1473. }
  1474. }
  1475. /**
  1476. * Function to be called when we decide that an
  1477. * external IP address as told to us by a STUN
  1478. * server has gone stale.
  1479. *
  1480. * @param cls the `struct StunExternalIP` to drop
  1481. */
  1482. static void
  1483. stun_ip_timeout (void *cls)
  1484. {
  1485. struct StunExternalIP *se = cls;
  1486. se->timeout_task = NULL;
  1487. notify_clients_stun_change (&se->external_addr,
  1488. GNUNET_NO);
  1489. GNUNET_CONTAINER_DLL_remove (se_head,
  1490. se_tail,
  1491. se);
  1492. GNUNET_free (se);
  1493. }
  1494. /**
  1495. * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
  1496. * client.
  1497. *
  1498. * @param cls client who sent the message
  1499. * @param message the message received
  1500. */
  1501. static void
  1502. handle_stun (void *cls,
  1503. const struct GNUNET_NAT_HandleStunMessage *message)
  1504. {
  1505. struct ClientHandle *ch = cls;
  1506. const char *buf = (const char *) &message[1];
  1507. const struct sockaddr *sa;
  1508. const void *payload;
  1509. size_t sa_len;
  1510. size_t payload_size;
  1511. struct sockaddr_in external_addr;
  1512. sa_len = ntohs (message->sender_addr_size);
  1513. payload_size = ntohs (message->payload_size);
  1514. sa = (const struct sockaddr *) &buf[0];
  1515. payload = (const struct sockaddr *) &buf[sa_len];
  1516. switch (sa->sa_family)
  1517. {
  1518. case AF_INET:
  1519. if (sa_len != sizeof (struct sockaddr_in))
  1520. {
  1521. GNUNET_break (0);
  1522. GNUNET_SERVICE_client_drop (ch->client);
  1523. return;
  1524. }
  1525. break;
  1526. case AF_INET6:
  1527. if (sa_len != sizeof (struct sockaddr_in6))
  1528. {
  1529. GNUNET_break (0);
  1530. GNUNET_SERVICE_client_drop (ch->client);
  1531. return;
  1532. }
  1533. break;
  1534. }
  1535. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1536. "Received HANDLE_STUN message from client\n");
  1537. if (GNUNET_OK ==
  1538. GNUNET_NAT_stun_handle_packet_ (payload,
  1539. payload_size,
  1540. &external_addr))
  1541. {
  1542. /* We now know that a server at "sa" claims that
  1543. we are visible at IP "external_addr".
  1544. We should (for some fixed period of time) tell
  1545. all of our clients that listen to a NAT'ed address
  1546. that they might want to consider the given 'external_ip'
  1547. as their public IP address (this includes TCP and UDP
  1548. clients, even if only UDP sends STUN requests).
  1549. If we do not get a renewal, the "external_addr" should be
  1550. removed again. The timeout frequency should be configurable
  1551. (with a sane default), so that the UDP plugin can tell how
  1552. often to re-request STUN.
  1553. */
  1554. struct StunExternalIP *se;
  1555. /* Check if we had a prior response from this STUN server */
  1556. for (se = se_head; NULL != se; se = se->next)
  1557. {
  1558. if ( (se->stun_server_addr_len != sa_len) ||
  1559. (0 != memcmp (sa,
  1560. &se->stun_server_addr,
  1561. sa_len)) )
  1562. continue; /* different STUN server */
  1563. if (0 != memcmp (&external_addr,
  1564. &se->external_addr,
  1565. sizeof (struct sockaddr_in)))
  1566. {
  1567. /* external IP changed, update! */
  1568. notify_clients_stun_change (&se->external_addr,
  1569. GNUNET_NO);
  1570. se->external_addr = external_addr;
  1571. notify_clients_stun_change (&se->external_addr,
  1572. GNUNET_YES);
  1573. }
  1574. /* update timeout */
  1575. GNUNET_SCHEDULER_cancel (se->timeout_task);
  1576. se->timeout_task
  1577. = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
  1578. &stun_ip_timeout,
  1579. se);
  1580. return;
  1581. }
  1582. /* STUN server is completely new, create fresh entry */
  1583. se = GNUNET_new (struct StunExternalIP);
  1584. se->external_addr = external_addr;
  1585. GNUNET_memcpy (&se->stun_server_addr,
  1586. sa,
  1587. sa_len);
  1588. se->stun_server_addr_len = sa_len;
  1589. se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
  1590. &stun_ip_timeout,
  1591. se);
  1592. GNUNET_CONTAINER_DLL_insert (se_head,
  1593. se_tail,
  1594. se);
  1595. notify_clients_stun_change (&se->external_addr,
  1596. GNUNET_NO);
  1597. }
  1598. GNUNET_SERVICE_client_continue (ch->client);
  1599. }
  1600. /**
  1601. * Check validity of
  1602. * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
  1603. * client.
  1604. *
  1605. * @param cls client who sent the message
  1606. * @param message the message received
  1607. * @return #GNUNET_OK if message is well-formed
  1608. */
  1609. static int
  1610. check_request_connection_reversal (void *cls,
  1611. const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
  1612. {
  1613. size_t expect;
  1614. expect = ntohs (message->local_addr_size)
  1615. + ntohs (message->remote_addr_size);
  1616. if (ntohs (message->header.size) - sizeof (*message) != expect)
  1617. {
  1618. GNUNET_break (0);
  1619. return GNUNET_SYSERR;
  1620. }
  1621. return GNUNET_OK;
  1622. }
  1623. /**
  1624. * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
  1625. * message from client.
  1626. *
  1627. * @param cls client who sent the message
  1628. * @param message the message received
  1629. */
  1630. static void
  1631. handle_request_connection_reversal (void *cls,
  1632. const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
  1633. {
  1634. struct ClientHandle *ch = cls;
  1635. const char *buf = (const char *) &message[1];
  1636. size_t local_sa_len = ntohs (message->local_addr_size);
  1637. size_t remote_sa_len = ntohs (message->remote_addr_size);
  1638. struct sockaddr_in l4;
  1639. struct sockaddr_in r4;
  1640. int ret;
  1641. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1642. "Received REQUEST CONNECTION REVERSAL message from client\n");
  1643. if (local_sa_len != sizeof (struct sockaddr_in))
  1644. {
  1645. GNUNET_break_op (0);
  1646. GNUNET_SERVICE_client_drop (ch->client);
  1647. return;
  1648. }
  1649. if (remote_sa_len != sizeof (struct sockaddr_in))
  1650. {
  1651. GNUNET_break_op (0);
  1652. GNUNET_SERVICE_client_drop (ch->client);
  1653. return;
  1654. }
  1655. GNUNET_memcpy (&l4,
  1656. buf,
  1657. sizeof (struct sockaddr_in));
  1658. GNUNET_break_op (AF_INET == l4.sin_family);
  1659. buf += sizeof (struct sockaddr_in);
  1660. GNUNET_memcpy (&r4,
  1661. buf,
  1662. sizeof (struct sockaddr_in));
  1663. GNUNET_break_op (AF_INET == r4.sin_family);
  1664. ret = GN_request_connection_reversal (&l4.sin_addr,
  1665. ntohs (l4.sin_port),
  1666. &r4.sin_addr);
  1667. if (GNUNET_OK != ret)
  1668. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1669. _("Connection reversal request failed\n"));
  1670. GNUNET_SERVICE_client_continue (ch->client);
  1671. }
  1672. /**
  1673. * Task run during shutdown.
  1674. *
  1675. * @param cls unused
  1676. */
  1677. static void
  1678. shutdown_task (void *cls)
  1679. {
  1680. struct StunExternalIP *se;
  1681. while (NULL != (se = se_head))
  1682. {
  1683. GNUNET_CONTAINER_DLL_remove (se_head,
  1684. se_tail,
  1685. se);
  1686. GNUNET_SCHEDULER_cancel (se->timeout_task);
  1687. GNUNET_free (se);
  1688. }
  1689. GN_nat_status_changed (GNUNET_NO);
  1690. if (NULL != scan_task)
  1691. {
  1692. GNUNET_SCHEDULER_cancel (scan_task);
  1693. scan_task = NULL;
  1694. }
  1695. if (NULL != stats)
  1696. {
  1697. GNUNET_STATISTICS_destroy (stats,
  1698. GNUNET_NO);
  1699. stats = NULL;
  1700. }
  1701. destroy_lal ();
  1702. }
  1703. /**
  1704. * Setup NAT service.
  1705. *
  1706. * @param cls closure
  1707. * @param c configuration to use
  1708. * @param service the initialized service
  1709. */
  1710. static void
  1711. run (void *cls,
  1712. const struct GNUNET_CONFIGURATION_Handle *c,
  1713. struct GNUNET_SERVICE_Handle *service)
  1714. {
  1715. cfg = c;
  1716. if (GNUNET_OK !=
  1717. GNUNET_CONFIGURATION_get_value_time (cfg,
  1718. "NAT",
  1719. "STUN_STALE",
  1720. &stun_stale_timeout))
  1721. stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
  1722. /* Check for UPnP */
  1723. enable_upnp
  1724. = GNUNET_CONFIGURATION_get_value_yesno (cfg,
  1725. "NAT",
  1726. "ENABLE_UPNP");
  1727. if (GNUNET_YES == enable_upnp)
  1728. {
  1729. /* check if it works */
  1730. if (GNUNET_SYSERR ==
  1731. GNUNET_OS_check_helper_binary ("upnpc",
  1732. GNUNET_NO,
  1733. NULL))
  1734. {
  1735. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1736. _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
  1737. enable_upnp = GNUNET_SYSERR;
  1738. }
  1739. }
  1740. if (GNUNET_OK !=
  1741. GNUNET_CONFIGURATION_get_value_time (cfg,
  1742. "nat",
  1743. "DYNDNS_FREQUENCY",
  1744. &dyndns_frequency))
  1745. dyndns_frequency = DYNDNS_FREQUENCY;
  1746. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  1747. NULL);
  1748. stats = GNUNET_STATISTICS_create ("nat",
  1749. cfg);
  1750. scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
  1751. NULL);
  1752. }
  1753. /**
  1754. * Callback called when a client connects to the service.
  1755. *
  1756. * @param cls closure for the service
  1757. * @param c the new client that connected to the service
  1758. * @param mq the message queue used to send messages to the client
  1759. * @return a `struct ClientHandle`
  1760. */
  1761. static void *
  1762. client_connect_cb (void *cls,
  1763. struct GNUNET_SERVICE_Client *c,
  1764. struct GNUNET_MQ_Handle *mq)
  1765. {
  1766. struct ClientHandle *ch;
  1767. ch = GNUNET_new (struct ClientHandle);
  1768. ch->mq = mq;
  1769. ch->client = c;
  1770. GNUNET_CONTAINER_DLL_insert (ch_head,
  1771. ch_tail,
  1772. ch);
  1773. return ch;
  1774. }
  1775. /**
  1776. * Callback called when a client disconnected from the service
  1777. *
  1778. * @param cls closure for the service
  1779. * @param c the client that disconnected
  1780. * @param internal_cls a `struct ClientHandle *`
  1781. */
  1782. static void
  1783. client_disconnect_cb (void *cls,
  1784. struct GNUNET_SERVICE_Client *c,
  1785. void *internal_cls)
  1786. {
  1787. struct ClientHandle *ch = internal_cls;
  1788. struct LocalAddressList *lal;
  1789. GNUNET_CONTAINER_DLL_remove (ch_head,
  1790. ch_tail,
  1791. ch);
  1792. for (unsigned int i=0;i<ch->num_caddrs;i++)
  1793. {
  1794. if (NULL != ch->caddrs[i].mh)
  1795. {
  1796. GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
  1797. ch->caddrs[i].mh = NULL;
  1798. }
  1799. }
  1800. GNUNET_free_non_null (ch->caddrs);
  1801. while (NULL != (lal = ch->ext_addr_head))
  1802. {
  1803. GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
  1804. ch->ext_addr_tail,
  1805. lal);
  1806. GNUNET_free (lal);
  1807. }
  1808. if (NULL != ch->ext_dns_task)
  1809. {
  1810. GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
  1811. ch->ext_dns_task = NULL;
  1812. }
  1813. if (NULL != ch->external_monitor)
  1814. {
  1815. GN_external_ipv4_monitor_stop (ch->external_monitor);
  1816. ch->external_monitor = NULL;
  1817. }
  1818. if (NULL != ch->ext_dns)
  1819. {
  1820. GNUNET_RESOLVER_request_cancel (ch->ext_dns);
  1821. ch->ext_dns = NULL;
  1822. }
  1823. GNUNET_free_non_null (ch->hole_external);
  1824. GNUNET_free_non_null (ch->section_name);
  1825. GNUNET_free (ch);
  1826. }
  1827. /**
  1828. * Define "main" method using service macro.
  1829. */
  1830. GNUNET_SERVICE_MAIN
  1831. ("nat",
  1832. GNUNET_SERVICE_OPTION_NONE,
  1833. &run,
  1834. &client_connect_cb,
  1835. &client_disconnect_cb,
  1836. NULL,
  1837. GNUNET_MQ_hd_var_size (register,
  1838. GNUNET_MESSAGE_TYPE_NAT_REGISTER,
  1839. struct GNUNET_NAT_RegisterMessage,
  1840. NULL),
  1841. GNUNET_MQ_hd_var_size (stun,
  1842. GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
  1843. struct GNUNET_NAT_HandleStunMessage,
  1844. NULL),
  1845. GNUNET_MQ_hd_var_size (request_connection_reversal,
  1846. GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
  1847. struct GNUNET_NAT_RequestConnectionReversalMessage,
  1848. NULL),
  1849. GNUNET_MQ_handler_end ());
  1850. #if defined(LINUX) && defined(__GLIBC__)
  1851. #include <malloc.h>
  1852. /**
  1853. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  1854. */
  1855. void __attribute__ ((constructor))
  1856. GNUNET_ARM_memory_init ()
  1857. {
  1858. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  1859. mallopt (M_TOP_PAD, 1 * 1024);
  1860. malloc_trim (0);
  1861. }
  1862. #endif
  1863. /* end of gnunet-service-nat.c */