use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / nt / nt.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015, 2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file nt/nt_api_scanner.c
22  * @brief LAN interface scanning to determine IPs in LAN
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_nt_lib.h"
29
30 /**
31  * How frequently do we scan the interfaces for changes to the addresses?
32  */
33 #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply ( \
34     GNUNET_TIME_UNIT_MINUTES, 2)
35
36
37 /**
38  * Convert a `enum GNUNET_NetworkType` to a string
39  *
40  * @param net the network type
41  * @return a string or NULL if invalid
42  */
43 const char *
44 GNUNET_NT_to_string (enum GNUNET_NetworkType net)
45 {
46   switch (net)
47   {
48   case GNUNET_NT_UNSPECIFIED:
49     return "UNSPECIFIED";
50
51   case GNUNET_NT_LOOPBACK:
52     return "LOOPBACK";
53
54   case GNUNET_NT_LAN:
55     return "LAN";
56
57   case GNUNET_NT_WAN:
58     return "WAN";
59
60   case GNUNET_NT_WLAN:
61     return "WLAN";
62
63   case GNUNET_NT_BT:
64     return "BLUETOOTH";
65
66   default:
67     return NULL;
68   }
69 }
70
71
72 /**
73  * We keep a list of our local networks so we can answer
74  * LAN vs. WAN questions.  Note: WLAN is not detected yet.
75  * (maybe we can do that heuristically based on interface
76  * name in the future?).
77  */
78 struct NT_Network
79 {
80   /**
81    * Kept in a DLL.
82    */
83   struct NT_Network *next;
84
85   /**
86    * Kept in a DLL.
87    */
88   struct NT_Network *prev;
89
90   /**
91    * Network address.
92    */
93   struct sockaddr *network;
94
95   /**
96    * Netmask to determine what is in the LAN.
97    */
98   struct sockaddr *netmask;
99
100   /**
101    * How long are @e network and @e netmask?
102    */
103   socklen_t length;
104 };
105
106
107 /**
108  * Handle to the interface scanner.
109  */
110 struct GNUNET_NT_InterfaceScanner
111 {
112   /**
113    * Head of LAN networks list.
114    */
115   struct NT_Network *net_head;
116
117   /**
118    * Tail of LAN networks list.
119    */
120   struct NT_Network *net_tail;
121
122   /**
123    * Task for periodically refreshing our LAN network list.
124    */
125   struct GNUNET_SCHEDULER_Task *interface_task;
126 };
127
128
129 /**
130  * Delete all entries from the current network list.
131  *
132  * @param is scanner to clean up
133  */
134 static void
135 delete_networks (struct GNUNET_NT_InterfaceScanner *is)
136 {
137   struct NT_Network *cur;
138
139   while (NULL != (cur = is->net_head))
140   {
141     GNUNET_CONTAINER_DLL_remove (is->net_head,
142                                  is->net_tail,
143                                  cur);
144     GNUNET_free (cur);
145   }
146 }
147
148
149 /**
150  * Function invoked for each interface found.  Adds the interface's
151  * network addresses to the respective DLL, so we can distinguish
152  * between LAN and WAN.
153  *
154  * @param cls closure with the `struct GNUNET_NT_InterfaceScanner`
155  * @param name name of the interface (can be NULL for unknown)
156  * @param isDefault is this presumably the default interface
157  * @param addr address of this interface (can be NULL for unknown or unassigned)
158  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
159  * @param netmask the network mask (can be NULL for unknown or unassigned)
160  * @param addrlen length of the address
161  * @return #GNUNET_OK to continue iteration
162  */
163 static int
164 interface_proc (void *cls,
165                 const char *name,
166                 int isDefault,
167                 const struct sockaddr *addr,
168                 const struct sockaddr *broadcast_addr,
169                 const struct sockaddr *netmask,
170                 socklen_t addrlen)
171 {
172   struct GNUNET_NT_InterfaceScanner *is = cls;
173   /* Calculate network */
174   struct NT_Network *net = NULL;
175
176   (void) name;
177   (void) isDefault;
178   (void) broadcast_addr;
179
180   /* Skipping IPv4 loopback addresses since we have special check  */
181   if (addr->sa_family == AF_INET)
182   {
183     const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
184
185     if ((a4->sin_addr.s_addr & htonl (0xff000000)) == htonl (0x7f000000))
186       return GNUNET_OK;
187   }
188   /* Skipping IPv6 loopback addresses since we have special check  */
189   if (addr->sa_family == AF_INET6)
190   {
191     const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
192     if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
193       return GNUNET_OK;
194   }
195
196   if (addr->sa_family == AF_INET)
197   {
198     const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr;
199     const struct sockaddr_in *netmask4 = (const struct sockaddr_in *) netmask;
200     struct sockaddr_in *tmp;
201     struct sockaddr_in network4;
202
203     net = GNUNET_malloc (sizeof(struct NT_Network) + 2 * sizeof(struct
204                                                                 sockaddr_in));
205     tmp = (struct sockaddr_in *) &net[1];
206     net->network = (struct sockaddr *) &tmp[0];
207     net->netmask = (struct sockaddr *) &tmp[1];
208     net->length = addrlen;
209
210     memset (&network4,
211             0,
212             sizeof(network4));
213     network4.sin_family = AF_INET;
214 #if HAVE_SOCKADDR_IN_SIN_LEN
215     network4.sin_len = sizeof(network4);
216 #endif
217     network4.sin_addr.s_addr = (addr4->sin_addr.s_addr
218                                 & netmask4->sin_addr.s_addr);
219
220     GNUNET_memcpy (net->netmask,
221                    netmask4,
222                    sizeof(struct sockaddr_in));
223     GNUNET_memcpy (net->network,
224                    &network4,
225                    sizeof(struct sockaddr_in));
226   }
227
228   if (addr->sa_family == AF_INET6)
229   {
230     const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
231     const struct sockaddr_in6 *netmask6 = (const struct sockaddr_in6 *) netmask;
232     struct sockaddr_in6 *tmp;
233     struct sockaddr_in6 network6;
234
235     net = GNUNET_malloc (sizeof(struct NT_Network) + 2 * sizeof(struct
236                                                                 sockaddr_in6));
237     tmp = (struct sockaddr_in6 *) &net[1];
238     net->network = (struct sockaddr *) &tmp[0];
239     net->netmask = (struct sockaddr *) &tmp[1];
240     net->length = addrlen;
241
242     memset (&network6, 0, sizeof(network6));
243     network6.sin6_family = AF_INET6;
244 #if HAVE_SOCKADDR_IN_SIN_LEN
245     network6.sin6_len = sizeof(network6);
246 #endif
247     unsigned int c = 0;
248     uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
249     uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
250     uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
251     for (c = 0; c < 4; c++)
252       net_elem[c] = addr_elem[c] & mask_elem[c];
253
254     GNUNET_memcpy (net->netmask,
255                    netmask6,
256                    sizeof(struct sockaddr_in6));
257     GNUNET_memcpy (net->network,
258                    &network6,
259                    sizeof(struct sockaddr_in6));
260   }
261   if (NULL == net)
262     return GNUNET_OK; /* odd / unsupported address family */
263
264   /* Store in list */
265 #if VERBOSE_NT
266   char *netmask = GNUNET_strdup (GNUNET_a2s ((struct sockaddr *) net->netmask,
267                                              addrlen));
268   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
269                    "nt",
270                    "Adding network `%s', netmask `%s'\n",
271                    GNUNET_a2s ((struct sockaddr *) net->network,
272                                addrlen),
273                    netmask);
274   GNUNET_free (netmask);
275 #endif
276   GNUNET_CONTAINER_DLL_insert (is->net_head,
277                                is->net_tail,
278                                net);
279
280   return GNUNET_OK;
281 }
282
283
284 /**
285  * Periodically get list of network addresses from our interfaces.
286  *
287  * @param cls closure
288  */
289 static void
290 get_addresses (void *cls)
291 {
292   struct GNUNET_NT_InterfaceScanner *is = cls;
293
294   is->interface_task = NULL;
295   delete_networks (is);
296   GNUNET_OS_network_interfaces_list (&interface_proc,
297                                      is);
298   is->interface_task = GNUNET_SCHEDULER_add_delayed (
299     INTERFACE_PROCESSING_INTERVAL,
300     &get_addresses,
301     is);
302 }
303
304
305 /**
306  * Returns where the address is located: LAN or WAN or ...
307  *
308  * @param is the interface scanner handle
309  * @param addr address
310  * @param addrlen address length
311  * @return type of the network the address belongs to
312  */
313 enum GNUNET_NetworkType
314 GNUNET_NT_scanner_get_type (struct GNUNET_NT_InterfaceScanner *is,
315                             const struct sockaddr *addr,
316                             socklen_t addrlen)
317 {
318   struct NT_Network *cur = is->net_head;
319   enum GNUNET_NetworkType type = GNUNET_NT_UNSPECIFIED;
320
321   switch (addr->sa_family)
322   {
323   case AF_UNIX:
324     type = GNUNET_NT_LOOPBACK;
325     break;
326
327   case AF_INET:
328     {
329       const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
330
331       if ((a4->sin_addr.s_addr & htonl (0xff000000)) == htonl (0x7f000000))
332         type = GNUNET_NT_LOOPBACK;
333       break;
334     }
335
336   case AF_INET6:
337     {
338       const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
339
340       if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
341         type = GNUNET_NT_LOOPBACK;
342       break;
343     }
344
345   default:
346     GNUNET_break (0);
347     break;
348   }
349
350   /* Check local networks */
351   while ((NULL != cur) && (GNUNET_NT_UNSPECIFIED == type))
352   {
353     if (addrlen != cur->length)
354     {
355       cur = cur->next;
356       continue;
357     }
358     if (addr->sa_family == AF_INET)
359     {
360       const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
361       const struct sockaddr_in *net4 = (const struct
362                                         sockaddr_in *) cur->network;
363       const struct sockaddr_in *mask4 = (const struct
364                                          sockaddr_in *) cur->netmask;
365
366       if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) ==
367           net4->sin_addr.s_addr)
368         type = GNUNET_NT_LAN;
369     }
370     if (addr->sa_family == AF_INET6)
371     {
372       const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
373       const struct sockaddr_in6 *net6 = (const struct
374                                          sockaddr_in6 *) cur->network;
375       const struct sockaddr_in6 *mask6 = (const struct
376                                           sockaddr_in6 *) cur->netmask;
377
378       int res = GNUNET_YES;
379       int c = 0;
380       uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
381       uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
382       uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
383       for (c = 0; c < 4; c++)
384         if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
385           res = GNUNET_NO;
386
387       if (res == GNUNET_YES)
388         type = GNUNET_NT_LAN;
389     }
390     cur = cur->next;
391   }
392
393   /* no local network found for this address, default: WAN */
394   if (type == GNUNET_NT_UNSPECIFIED)
395     type = GNUNET_NT_WAN;
396   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
397                    "nt-scanner-api",
398                    "`%s' is in network `%s'\n",
399                    GNUNET_a2s (addr,
400                                addrlen),
401                    GNUNET_NT_to_string (type));
402   return type;
403 }
404
405
406 /**
407  * Initialize the interface scanner.
408  *
409  * @return interface scanner
410  */
411 struct GNUNET_NT_InterfaceScanner *
412 GNUNET_NT_scanner_init ()
413 {
414   struct GNUNET_NT_InterfaceScanner *is;
415
416   is = GNUNET_new (struct GNUNET_NT_InterfaceScanner);
417   GNUNET_OS_network_interfaces_list (&interface_proc,
418                                      is);
419   is->interface_task = GNUNET_SCHEDULER_add_delayed (
420     INTERFACE_PROCESSING_INTERVAL,
421     &get_addresses,
422     is);
423   return is;
424 }
425
426
427 /**
428  * Client is done with the interface scanner, release resources.
429  *
430  * @param is handle to release
431  */
432 void
433 GNUNET_NT_scanner_done (struct GNUNET_NT_InterfaceScanner *is)
434 {
435   if (NULL != is->interface_task)
436   {
437     GNUNET_SCHEDULER_cancel (is->interface_task);
438     is->interface_task = NULL;
439   }
440   delete_networks (is);
441   GNUNET_free (is);
442 }
443
444
445 /* end of nt.c */