ats_api_scanner.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/ats_api_scanner.c
  19. * @brief LAN interface scanning to determine IPs in LAN
  20. * @author Christian Grothoff
  21. * @author Matthias Wachs
  22. */
  23. #include "platform.h"
  24. #include "gnunet_ats_service.h"
  25. /**
  26. * How frequently do we scan the interfaces for changes to the addresses?
  27. */
  28. #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
  29. /**
  30. * Convert a `enum GNUNET_ATS_Network_Type` to a string
  31. *
  32. * @param net the network type
  33. * @return a string or NULL if invalid
  34. */
  35. const char *
  36. GNUNET_ATS_print_network_type (enum GNUNET_ATS_Network_Type net)
  37. {
  38. switch (net)
  39. {
  40. case GNUNET_ATS_NET_UNSPECIFIED:
  41. return "UNSPECIFIED";
  42. case GNUNET_ATS_NET_LOOPBACK:
  43. return "LOOPBACK";
  44. case GNUNET_ATS_NET_LAN:
  45. return "LAN";
  46. case GNUNET_ATS_NET_WAN:
  47. return "WAN";
  48. case GNUNET_ATS_NET_WLAN:
  49. return "WLAN";
  50. case GNUNET_ATS_NET_BT:
  51. return "BLUETOOTH";
  52. default:
  53. return NULL;
  54. }
  55. }
  56. /**
  57. * Convert a ATS property to a string
  58. *
  59. * @param type the property type
  60. * @return a string or NULL if invalid
  61. */
  62. const char *
  63. GNUNET_ATS_print_property_type (enum GNUNET_ATS_Property type)
  64. {
  65. switch (type)
  66. {
  67. case GNUNET_ATS_ARRAY_TERMINATOR:
  68. return "TERMINATOR";
  69. case GNUNET_ATS_UTILIZATION_OUT:
  70. return "UTILIZATION_UP";
  71. case GNUNET_ATS_UTILIZATION_IN:
  72. return "UTILIZATION_DOWN";
  73. case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
  74. return "UTILIZATION_PAYLOAD_UP";
  75. case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
  76. return "UTILIZATION_PAYLOAD_DOWN";
  77. case GNUNET_ATS_NETWORK_TYPE:
  78. return "NETWORK_TYPE";
  79. case GNUNET_ATS_QUALITY_NET_DELAY:
  80. return "DELAY";
  81. case GNUNET_ATS_QUALITY_NET_DISTANCE:
  82. return "DISTANCE";
  83. case GNUNET_ATS_COST_WAN:
  84. return "COST_WAN";
  85. case GNUNET_ATS_COST_LAN:
  86. return "COST_LAN";
  87. case GNUNET_ATS_COST_WLAN:
  88. return "COST_WLAN";
  89. default:
  90. return NULL;
  91. }
  92. }
  93. /**
  94. * We keep a list of our local networks so we can answer
  95. * LAN vs. WAN questions. Note: WLAN is not detected yet.
  96. * (maybe we can do that heuristically based on interface
  97. * name in the future?).
  98. */
  99. struct ATS_Network
  100. {
  101. /**
  102. * Kept in a DLL.
  103. */
  104. struct ATS_Network *next;
  105. /**
  106. * Kept in a DLL.
  107. */
  108. struct ATS_Network *prev;
  109. /**
  110. * Network address.
  111. */
  112. struct sockaddr *network;
  113. /**
  114. * Netmask to determine what is in the LAN.
  115. */
  116. struct sockaddr *netmask;
  117. /**
  118. * How long are @e network and @e netmask?
  119. */
  120. socklen_t length;
  121. };
  122. /**
  123. * Handle to the interface scanner.
  124. */
  125. struct GNUNET_ATS_InterfaceScanner
  126. {
  127. /**
  128. * Head of LAN networks list.
  129. */
  130. struct ATS_Network *net_head;
  131. /**
  132. * Tail of LAN networks list.
  133. */
  134. struct ATS_Network *net_tail;
  135. /**
  136. * Task for periodically refreshing our LAN network list.
  137. */
  138. struct GNUNET_SCHEDULER_Task *interface_task;
  139. };
  140. /**
  141. * Delete all entries from the current network list.
  142. *
  143. * @param is scanner to clean up
  144. */
  145. static void
  146. delete_networks (struct GNUNET_ATS_InterfaceScanner *is)
  147. {
  148. struct ATS_Network *cur;
  149. while (NULL != (cur = is->net_head))
  150. {
  151. GNUNET_CONTAINER_DLL_remove (is->net_head,
  152. is->net_tail,
  153. cur);
  154. GNUNET_free (cur);
  155. }
  156. }
  157. /**
  158. * Function invoked for each interface found. Adds the interface's
  159. * network addresses to the respective DLL, so we can distinguish
  160. * between LAN and WAN.
  161. *
  162. * @param cls closure with the `struct GNUNET_ATS_InterfaceScanner`
  163. * @param name name of the interface (can be NULL for unknown)
  164. * @param isDefault is this presumably the default interface
  165. * @param addr address of this interface (can be NULL for unknown or unassigned)
  166. * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
  167. * @param netmask the network mask (can be NULL for unknown or unassigned)
  168. * @param addrlen length of the address
  169. * @return #GNUNET_OK to continue iteration
  170. */
  171. static int
  172. interface_proc (void *cls,
  173. const char *name,
  174. int isDefault,
  175. const struct sockaddr *addr,
  176. const struct sockaddr *broadcast_addr,
  177. const struct sockaddr *netmask,
  178. socklen_t addrlen)
  179. {
  180. struct GNUNET_ATS_InterfaceScanner *is = cls;
  181. /* Calculate network */
  182. struct ATS_Network *net = NULL;
  183. /* Skipping IPv4 loopback addresses since we have special check */
  184. if (addr->sa_family == AF_INET)
  185. {
  186. const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
  187. if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
  188. return GNUNET_OK;
  189. }
  190. /* Skipping IPv6 loopback addresses since we have special check */
  191. if (addr->sa_family == AF_INET6)
  192. {
  193. const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
  194. if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
  195. return GNUNET_OK;
  196. }
  197. if (addr->sa_family == AF_INET)
  198. {
  199. const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr;
  200. const struct sockaddr_in *netmask4 = (const struct sockaddr_in *) netmask;
  201. struct sockaddr_in *tmp;
  202. struct sockaddr_in network4;
  203. net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
  204. tmp = (struct sockaddr_in *) &net[1];
  205. net->network = (struct sockaddr *) &tmp[0];
  206. net->netmask = (struct sockaddr *) &tmp[1];
  207. net->length = addrlen;
  208. memset (&network4, 0, sizeof (network4));
  209. network4.sin_family = AF_INET;
  210. #if HAVE_SOCKADDR_IN_SIN_LEN
  211. network4.sin_len = sizeof (network4);
  212. #endif
  213. network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
  214. memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
  215. memcpy (net->network, &network4, sizeof (struct sockaddr_in));
  216. }
  217. if (addr->sa_family == AF_INET6)
  218. {
  219. const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
  220. const struct sockaddr_in6 *netmask6 = (const struct sockaddr_in6 *) netmask;
  221. struct sockaddr_in6 * tmp;
  222. struct sockaddr_in6 network6;
  223. net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
  224. tmp = (struct sockaddr_in6 *) &net[1];
  225. net->network = (struct sockaddr *) &tmp[0];
  226. net->netmask = (struct sockaddr *) &tmp[1];
  227. net->length = addrlen;
  228. memset (&network6, 0, sizeof (network6));
  229. network6.sin6_family = AF_INET6;
  230. #if HAVE_SOCKADDR_IN_SIN_LEN
  231. network6.sin6_len = sizeof (network6);
  232. #endif
  233. unsigned int c = 0;
  234. uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
  235. uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
  236. uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
  237. for (c = 0; c < 4; c++)
  238. net_elem[c] = addr_elem[c] & mask_elem[c];
  239. memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
  240. memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
  241. }
  242. if (NULL == net)
  243. return GNUNET_OK; /* odd / unsupported address family */
  244. /* Store in list */
  245. #if VERBOSE_ATS
  246. char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
  247. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  248. "Adding network `%s', netmask `%s'\n",
  249. GNUNET_a2s ((struct sockaddr *) net->network,
  250. addrlen),
  251. netmask);
  252. GNUNET_free (netmask);
  253. #endif
  254. GNUNET_CONTAINER_DLL_insert (is->net_head,
  255. is->net_tail,
  256. net);
  257. return GNUNET_OK;
  258. }
  259. /**
  260. * Periodically get list of network addresses from our interfaces.
  261. *
  262. * @param cls closure
  263. * @param tc Task context
  264. */
  265. static void
  266. get_addresses (void *cls,
  267. const struct GNUNET_SCHEDULER_TaskContext *tc)
  268. {
  269. struct GNUNET_ATS_InterfaceScanner *is = cls;
  270. is->interface_task = NULL;
  271. delete_networks (is);
  272. GNUNET_OS_network_interfaces_list (&interface_proc,
  273. is);
  274. is->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL,
  275. &get_addresses,
  276. is);
  277. }
  278. /**
  279. * Returns where the address is located: LAN or WAN or ...
  280. *
  281. * @param is the interface scanner handle
  282. * @param addr address
  283. * @param addrlen address length
  284. * @return type of the network the address belongs to
  285. */
  286. enum GNUNET_ATS_Network_Type
  287. GNUNET_ATS_scanner_address_get_type (struct GNUNET_ATS_InterfaceScanner *is,
  288. const struct sockaddr *addr,
  289. socklen_t addrlen)
  290. {
  291. struct ATS_Network *cur = is->net_head;
  292. enum GNUNET_ATS_Network_Type type = GNUNET_ATS_NET_UNSPECIFIED;
  293. switch (addr->sa_family)
  294. {
  295. case AF_UNIX:
  296. type = GNUNET_ATS_NET_LOOPBACK;
  297. break;
  298. case AF_INET:
  299. {
  300. const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
  301. if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
  302. type = GNUNET_ATS_NET_LOOPBACK;
  303. break;
  304. }
  305. case AF_INET6:
  306. {
  307. const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
  308. if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
  309. type = GNUNET_ATS_NET_LOOPBACK;
  310. break;
  311. }
  312. default:
  313. GNUNET_break (0);
  314. break;
  315. }
  316. /* Check local networks */
  317. while ((NULL != cur) && (GNUNET_ATS_NET_UNSPECIFIED == type))
  318. {
  319. if (addrlen != cur->length)
  320. {
  321. cur = cur->next;
  322. continue;
  323. }
  324. if (addr->sa_family == AF_INET)
  325. {
  326. const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
  327. const struct sockaddr_in *net4 = (const struct sockaddr_in *) cur->network;
  328. const struct sockaddr_in *mask4 = (const struct sockaddr_in *) cur->netmask;
  329. if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr)
  330. type = GNUNET_ATS_NET_LAN;
  331. }
  332. if (addr->sa_family == AF_INET6)
  333. {
  334. const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
  335. const struct sockaddr_in6 *net6 = (const struct sockaddr_in6 *) cur->network;
  336. const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *) cur->netmask;
  337. int res = GNUNET_YES;
  338. int c = 0;
  339. uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
  340. uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
  341. uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
  342. for (c = 0; c < 4; c++)
  343. if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
  344. res = GNUNET_NO;
  345. if (res == GNUNET_YES)
  346. type = GNUNET_ATS_NET_LAN;
  347. }
  348. cur = cur->next;
  349. }
  350. /* no local network found for this address, default: WAN */
  351. if (type == GNUNET_ATS_NET_UNSPECIFIED)
  352. type = GNUNET_ATS_NET_WAN;
  353. GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
  354. "ats-scheduling-api",
  355. "`%s' is in network `%s'\n",
  356. GNUNET_a2s (addr,
  357. addrlen),
  358. GNUNET_ATS_print_network_type (type));
  359. return type;
  360. }
  361. /**
  362. * Initialize the interface scanner.
  363. *
  364. * @return interface scanner
  365. */
  366. struct GNUNET_ATS_InterfaceScanner *
  367. GNUNET_ATS_scanner_init ()
  368. {
  369. struct GNUNET_ATS_InterfaceScanner *is;
  370. is = GNUNET_new (struct GNUNET_ATS_InterfaceScanner);
  371. GNUNET_OS_network_interfaces_list (&interface_proc,
  372. is);
  373. is->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL,
  374. &get_addresses,
  375. is);
  376. return is;
  377. }
  378. /**
  379. * Client is done with the interface scanner, release resources.
  380. *
  381. * @param is handle to release
  382. */
  383. void
  384. GNUNET_ATS_scanner_done (struct GNUNET_ATS_InterfaceScanner *is)
  385. {
  386. if (NULL != is->interface_task)
  387. {
  388. GNUNET_SCHEDULER_cancel (is->interface_task);
  389. is->interface_task = NULL;
  390. }
  391. delete_networks (is);
  392. GNUNET_free (is);
  393. }
  394. /* end of ats_api_scanner.c */