gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gnetworkmonitorbase.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright 2011 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "config.h"
22
23 #include "gnetworkmonitorbase.h"
24 #include "ginetaddress.h"
25 #include "ginetaddressmask.h"
26 #include "ginetsocketaddress.h"
27 #include "ginitable.h"
28 #include "gioerror.h"
29 #include "giomodule-priv.h"
30 #include "gnetworkmonitor.h"
31 #include "gsocketaddressenumerator.h"
32 #include "gsocketconnectable.h"
33 #include "gtask.h"
34 #include "glibintl.h"
35
36 static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
37 static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);
38
39 enum
40 {
41   PROP_0,
42
43   PROP_NETWORK_AVAILABLE,
44   PROP_NETWORK_METERED,
45   PROP_CONNECTIVITY
46 };
47
48 struct _GNetworkMonitorBasePrivate
49 {
50   GHashTable   *networks  /* (element-type GInetAddressMask) (owned) */;
51   gboolean      have_ipv4_default_route;
52   gboolean      have_ipv6_default_route;
53   gboolean      is_available;
54
55   GMainContext *context;
56   GSource      *network_changed_source;
57   gboolean      initializing;
58 };
59
60 static guint network_changed_signal = 0;
61
62 static void queue_network_changed (GNetworkMonitorBase *monitor);
63 static guint inet_address_mask_hash (gconstpointer key);
64 static gboolean inet_address_mask_equal (gconstpointer a,
65                                          gconstpointer b);
66
67 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
68                          G_ADD_PRIVATE (GNetworkMonitorBase)
69                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
70                                                 g_network_monitor_base_initable_iface_init)
71                          G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
72                                                 g_network_monitor_base_iface_init)
73                          _g_io_modules_ensure_extension_points_registered ();
74                          g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
75                                                          g_define_type_id,
76                                                          "base",
77                                                          0))
78
79 static void
80 g_network_monitor_base_init (GNetworkMonitorBase *monitor)
81 {
82   monitor->priv = g_network_monitor_base_get_instance_private (monitor);
83   monitor->priv->networks = g_hash_table_new_full (inet_address_mask_hash,
84                                                    inet_address_mask_equal,
85                                                    g_object_unref, NULL);
86   monitor->priv->context = g_main_context_get_thread_default ();
87   if (monitor->priv->context)
88     g_main_context_ref (monitor->priv->context);
89
90   monitor->priv->initializing = TRUE;
91 }
92
93 static void
94 g_network_monitor_base_constructed (GObject *object)
95 {
96   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
97
98   if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
99     {
100       GInetAddressMask *mask;
101
102       /* We're the dumb base class, not a smarter subclass. So just
103        * assume that the network is available.
104        */
105       mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
106       g_network_monitor_base_add_network (monitor, mask);
107       g_object_unref (mask);
108
109       mask = g_inet_address_mask_new_from_string ("::/0", NULL);
110       if (mask)
111         {
112           /* On some environments (for example Windows without IPv6 support
113            * enabled) the string "::/0" can't be processed and causes
114            * g_inet_address_mask_new_from_string to return NULL */
115           g_network_monitor_base_add_network (monitor, mask);
116           g_object_unref (mask);
117         }
118     }
119 }
120
121 static void
122 g_network_monitor_base_get_property (GObject    *object,
123                                      guint       prop_id,
124                                      GValue     *value,
125                                      GParamSpec *pspec)
126 {
127   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
128
129   switch (prop_id)
130     {
131     case PROP_NETWORK_AVAILABLE:
132       g_value_set_boolean (value, monitor->priv->is_available);
133       break;
134
135     case PROP_NETWORK_METERED:
136       /* Default to FALSE in the unknown case. */
137       g_value_set_boolean (value, FALSE);
138       break;
139
140     case PROP_CONNECTIVITY:
141       g_value_set_enum (value,
142                         monitor->priv->is_available ?
143                         G_NETWORK_CONNECTIVITY_FULL :
144                         G_NETWORK_CONNECTIVITY_LOCAL);
145       break;
146
147     default:
148       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149       break;
150     }
151
152 }
153
154 static void
155 g_network_monitor_base_finalize (GObject *object)
156 {
157   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
158
159   g_hash_table_unref (monitor->priv->networks);
160   if (monitor->priv->network_changed_source)
161     {
162       g_source_destroy (monitor->priv->network_changed_source);
163       g_source_unref (monitor->priv->network_changed_source);
164     }
165   if (monitor->priv->context)
166     g_main_context_unref (monitor->priv->context);
167
168   G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
169 }
170
171 static void
172 g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
173 {
174   GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
175
176   gobject_class->constructed  = g_network_monitor_base_constructed;
177   gobject_class->get_property = g_network_monitor_base_get_property;
178   gobject_class->finalize     = g_network_monitor_base_finalize;
179
180   g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
181   g_object_class_override_property (gobject_class, PROP_NETWORK_METERED, "network-metered");
182   g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity");
183 }
184
185 static gboolean
186 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
187                                            GSocketAddress *sockaddr)
188 {
189   GInetAddress *iaddr;
190   GHashTableIter iter;
191   gpointer key;
192
193   if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
194     return FALSE;
195
196   iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
197   g_hash_table_iter_init (&iter, base->priv->networks);
198   while (g_hash_table_iter_next (&iter, &key, NULL))
199     {
200       GInetAddressMask *mask = key;
201       if (g_inet_address_mask_matches (mask, iaddr))
202         return TRUE;
203     }
204
205   return FALSE;
206 }
207
208 static gboolean
209 g_network_monitor_base_can_reach (GNetworkMonitor      *monitor,
210                                   GSocketConnectable   *connectable,
211                                   GCancellable         *cancellable,
212                                   GError              **error)
213 {
214   GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
215   GSocketAddressEnumerator *enumerator;
216   GSocketAddress *addr;
217
218   if (g_hash_table_size (base->priv->networks) == 0)
219     {
220       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
221                            _("Network unreachable"));
222       return FALSE;
223     }
224
225   enumerator = g_socket_connectable_proxy_enumerate (connectable);
226   addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
227   if (!addr)
228     {
229       /* Either the user cancelled, or DNS resolution failed */
230       g_object_unref (enumerator);
231       return FALSE;
232     }
233
234   if (base->priv->have_ipv4_default_route &&
235       base->priv->have_ipv6_default_route)
236     {
237       g_object_unref (enumerator);
238       g_object_unref (addr);
239       return TRUE;
240     }
241
242   while (addr)
243     {
244       if (g_network_monitor_base_can_reach_sockaddr (base, addr))
245         {
246           g_object_unref (addr);
247           g_object_unref (enumerator);
248           return TRUE;
249         }
250
251       g_object_unref (addr);
252       addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
253     }
254   g_object_unref (enumerator);
255
256   if (error && !*error)
257     {
258       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
259                            _("Host unreachable"));
260     }
261   return FALSE;
262 }
263
264 static void
265 can_reach_async_got_address (GObject      *object,
266                              GAsyncResult *result,
267                              gpointer      user_data)
268 {
269   GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object);
270   GTask *task = user_data;
271   GNetworkMonitorBase *base = g_task_get_source_object (task);
272   GSocketAddress *addr;
273   GError *error = NULL;
274
275   addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
276   if (!addr)
277     {
278       if (error)
279         {
280           /* Either the user cancelled, or DNS resolution failed */
281           g_task_return_error (task, error);
282           g_object_unref (task);
283           return;
284         }
285       else
286         {
287           /* Resolved all addresses, none matched */
288           g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
289                                    _("Host unreachable"));
290           g_object_unref (task);
291           return;
292         }
293     }
294
295   if (g_network_monitor_base_can_reach_sockaddr (base, addr))
296     {
297       g_object_unref (addr);
298       g_task_return_boolean (task, TRUE);
299       g_object_unref (task);
300       return;
301     }
302   g_object_unref (addr);
303
304   g_socket_address_enumerator_next_async (enumerator,
305                                           g_task_get_cancellable (task),
306                                           can_reach_async_got_address, task);
307 }
308
309 static void
310 g_network_monitor_base_can_reach_async (GNetworkMonitor     *monitor,
311                                         GSocketConnectable  *connectable,
312                                         GCancellable        *cancellable,
313                                         GAsyncReadyCallback  callback,
314                                         gpointer             user_data)
315 {
316   GTask *task;
317   GSocketAddressEnumerator *enumerator;
318
319   task = g_task_new (monitor, cancellable, callback, user_data);
320   g_task_set_source_tag (task, g_network_monitor_base_can_reach_async);
321
322   if (g_hash_table_size (G_NETWORK_MONITOR_BASE (monitor)->priv->networks) == 0)
323     {
324       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
325                                _("Network unreachable"));
326       g_object_unref (task);
327       return;
328     }
329
330   enumerator = g_socket_connectable_proxy_enumerate (connectable);
331   g_socket_address_enumerator_next_async (enumerator, cancellable,
332                                           can_reach_async_got_address, task);
333   g_object_unref (enumerator);
334 }
335
336 static gboolean
337 g_network_monitor_base_can_reach_finish (GNetworkMonitor  *monitor,
338                                          GAsyncResult     *result,
339                                          GError          **error)
340 {
341   g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
342
343   return g_task_propagate_boolean (G_TASK (result), error);
344 }
345
346 static void
347 g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
348 {
349   monitor_iface->can_reach = g_network_monitor_base_can_reach;
350   monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async;
351   monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish;
352
353   network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
354 }
355
356 static gboolean
357 g_network_monitor_base_initable_init (GInitable     *initable,
358                                       GCancellable  *cancellable,
359                                       GError       **error)
360 {
361   GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (initable);
362
363   base->priv->initializing = FALSE;
364
365   return TRUE;
366 }
367
368 static void
369 g_network_monitor_base_initable_iface_init (GInitableIface *iface)
370 {
371   iface->init = g_network_monitor_base_initable_init;
372 }
373
374 static guint
375 inet_address_mask_hash (gconstpointer key)
376 {
377   GInetAddressMask *mask = G_INET_ADDRESS_MASK (key);
378   guint addr_hash;
379   guint mask_length = g_inet_address_mask_get_length (mask);
380   GInetAddress *addr = g_inet_address_mask_get_address (mask);
381   const guint8 *bytes = g_inet_address_to_bytes (addr);
382   gsize bytes_length = g_inet_address_get_native_size (addr);
383
384   union
385     {
386       const guint8 *bytes;
387       guint32 *hash32;
388       guint64 *hash64;
389     } integerifier;
390
391   /* If we can fit the entire address into the hash key, do it. Don’t worry
392    * about endianness; the address should always be in network endianness. */
393   if (bytes_length == sizeof (guint32))
394     {
395       integerifier.bytes = bytes;
396       addr_hash = *integerifier.hash32;
397     }
398   else if (bytes_length == sizeof (guint64))
399     {
400       integerifier.bytes = bytes;
401       addr_hash = *integerifier.hash64;
402     }
403   else
404     {
405       gsize i;
406
407       /* Otherwise, fall back to adding the bytes together. We do this, rather
408        * than XORing them, as routes often have repeated tuples which would
409        * cancel out under XOR. */
410       addr_hash = 0;
411       for (i = 0; i < bytes_length; i++)
412         addr_hash += bytes[i];
413     }
414
415   return addr_hash + mask_length;;
416 }
417
418 static gboolean
419 inet_address_mask_equal (gconstpointer a,
420                          gconstpointer b)
421 {
422   GInetAddressMask *mask_a = G_INET_ADDRESS_MASK (a);
423   GInetAddressMask *mask_b = G_INET_ADDRESS_MASK (b);
424
425   return g_inet_address_mask_equal (mask_a, mask_b);
426 }
427
428 static gboolean
429 emit_network_changed (gpointer user_data)
430 {
431   GNetworkMonitorBase *monitor = user_data;
432   gboolean is_available;
433
434   if (g_source_is_destroyed (g_main_current_source ()))
435     return FALSE;
436
437   g_object_ref (monitor);
438
439   is_available = (monitor->priv->have_ipv4_default_route ||
440                   monitor->priv->have_ipv6_default_route);
441   if (monitor->priv->is_available != is_available)
442     {
443       monitor->priv->is_available = is_available;
444       g_object_notify (G_OBJECT (monitor), "network-available");
445     }
446
447   g_signal_emit (monitor, network_changed_signal, 0, is_available);
448
449   g_source_unref (monitor->priv->network_changed_source);
450   monitor->priv->network_changed_source = NULL;
451
452   g_object_unref (monitor);
453   return FALSE;
454 }
455
456 static void
457 queue_network_changed (GNetworkMonitorBase *monitor)
458 {
459   if (!monitor->priv->network_changed_source &&
460       !monitor->priv->initializing)
461     {
462       GSource *source;
463
464       source = g_idle_source_new ();
465       /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
466        * network-change-related notifications coming in at
467        * G_PRIORITY_DEFAULT will get coalesced into one signal
468        * emission.
469        */
470       g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
471       g_source_set_callback (source, emit_network_changed, monitor, NULL);
472       g_source_set_static_name (source, "[gio] emit_network_changed");
473       g_source_attach (source, monitor->priv->context);
474       monitor->priv->network_changed_source = source;
475     }
476
477   /* Normally we wait to update is_available until we emit the signal,
478    * to keep things consistent. But when we're first creating the
479    * object, we want it to be correct right away.
480    */
481   if (monitor->priv->initializing)
482     {
483       monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
484                                      monitor->priv->have_ipv6_default_route);
485     }
486 }
487
488 /**
489  * g_network_monitor_base_add_network:
490  * @monitor: the #GNetworkMonitorBase
491  * @network: (transfer none): a #GInetAddressMask
492  *
493  * Adds @network to @monitor's list of available networks.
494  *
495  * Since: 2.32
496  */
497 void
498 g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
499                                     GInetAddressMask    *network)
500 {
501   if (!g_hash_table_add (monitor->priv->networks, g_object_ref (network)))
502     return;
503
504   if (g_inet_address_mask_get_length (network) == 0)
505     {
506       switch (g_inet_address_mask_get_family (network))
507         {
508         case G_SOCKET_FAMILY_IPV4:
509           monitor->priv->have_ipv4_default_route = TRUE;
510           break;
511         case G_SOCKET_FAMILY_IPV6:
512           monitor->priv->have_ipv6_default_route = TRUE;
513           break;
514         default:
515           break;
516         }
517     }
518
519   /* Don't emit network-changed when multicast-link-local routing
520    * changes. This rather arbitrary decision is mostly because it
521    * seems to change quite often...
522    */
523   if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
524     return;
525
526   queue_network_changed (monitor);
527 }
528
529 /**
530  * g_network_monitor_base_remove_network:
531  * @monitor: the #GNetworkMonitorBase
532  * @network: a #GInetAddressMask
533  *
534  * Removes @network from @monitor's list of available networks.
535  *
536  * Since: 2.32
537  */
538 void
539 g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
540                                        GInetAddressMask    *network)
541 {
542   if (!g_hash_table_remove (monitor->priv->networks, network))
543     return;
544
545   if (g_inet_address_mask_get_length (network) == 0)
546     {
547       switch (g_inet_address_mask_get_family (network))
548         {
549         case G_SOCKET_FAMILY_IPV4:
550           monitor->priv->have_ipv4_default_route = FALSE;
551           break;
552         case G_SOCKET_FAMILY_IPV6:
553           monitor->priv->have_ipv6_default_route = FALSE;
554           break;
555         default:
556           break;
557         }
558     }
559
560   queue_network_changed (monitor);
561 }
562
563 /**
564  * g_network_monitor_base_set_networks:
565  * @monitor: the #GNetworkMonitorBase
566  * @networks: (array length=length): an array of #GInetAddressMask
567  * @length: length of @networks
568  *
569  * Drops @monitor's current list of available networks and replaces
570  * it with @networks.
571  */
572 void
573 g_network_monitor_base_set_networks (GNetworkMonitorBase  *monitor,
574                                      GInetAddressMask    **networks,
575                                      gint                  length)
576 {
577   int i;
578
579   g_hash_table_remove_all (monitor->priv->networks);
580   monitor->priv->have_ipv4_default_route = FALSE;
581   monitor->priv->have_ipv6_default_route = FALSE;
582
583   for (i = 0; i < length; i++)
584     g_network_monitor_base_add_network (monitor, networks[i]);
585 }