| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2011 Red Hat, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2022-05-18 09:12:45 +01:00
										 |  |  |  * SPDX-License-Identifier: LGPL-2.1-or-later | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							| 
									
										
										
										
											2013-10-01 05:19:55 -07:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2025-04-21 22:28:49 +00:00
										 |  |  | #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
 | 
					
						
							|  |  |  | #include <sys/sysctl.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "gnetworkmonitornetlink.h"
 | 
					
						
							|  |  |  | #include "gcredentials.h"
 | 
					
						
							|  |  |  | #include "ginetaddressmask.h"
 | 
					
						
							|  |  |  | #include "ginitable.h"
 | 
					
						
							|  |  |  | #include "giomodule-priv.h"
 | 
					
						
							|  |  |  | #include "glibintl.h"
 | 
					
						
							| 
									
										
										
										
											2013-01-25 12:05:26 -05:00
										 |  |  | #include "glib/gstdio.h"
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | #include "gnetworkingprivate.h"
 | 
					
						
							|  |  |  | #include "gnetworkmonitor.h"
 | 
					
						
							|  |  |  | #include "gsocket.h"
 | 
					
						
							|  |  |  | #include "gunixcredentialsmessage.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-12 15:06:41 +01:00
										 |  |  | /* must come at the end to pick system includes from
 | 
					
						
							|  |  |  |  * gnetworkingprivate.h */ | 
					
						
							| 
									
										
										
										
											2024-10-29 21:18:36 +03:00
										 |  |  | #ifdef HAVE_LINUX_NETLINK_H
 | 
					
						
							| 
									
										
										
										
											2011-12-12 15:06:41 +01:00
										 |  |  | #include <linux/netlink.h>
 | 
					
						
							|  |  |  | #include <linux/rtnetlink.h>
 | 
					
						
							| 
									
										
										
										
											2024-10-29 21:18:36 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2025-03-10 12:01:52 +00:00
										 |  |  | #if defined(HAVE_NETLINK_NETLINK_H) && defined(HAVE_NETLINK_NETLINK_ROUTE_H)
 | 
					
						
							| 
									
										
										
										
											2024-10-29 21:18:36 +03:00
										 |  |  | #include <netlink/netlink.h>
 | 
					
						
							|  |  |  | #include <netlink/netlink_route.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-12-12 15:06:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 15:27:00 +00:00
										 |  |  | static GInitableIface *initable_parent_iface; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface); | 
					
						
							|  |  |  | static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _GNetworkMonitorNetlinkPrivate | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GSocket *sock; | 
					
						
							|  |  |  |   GSource *source, *dump_source; | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   GMainContext *context; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   GPtrArray *dump_networks; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  | static gboolean read_netlink_messages (GNetworkMonitorNetlink  *nl, | 
					
						
							|  |  |  |                                        GError                 **error); | 
					
						
							|  |  |  | static gboolean read_netlink_messages_callback (GSocket             *socket, | 
					
						
							|  |  |  |                                                 GIOCondition         condition, | 
					
						
							|  |  |  |                                                 gpointer             user_data); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | static gboolean request_dump (GNetworkMonitorNetlink  *nl, | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                               GError                 **error); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-11 00:29:58 +01:00
										 |  |  | #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
 | 
					
						
							|  |  |  | G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE, | 
					
						
							|  |  |  |                          G_ADD_PRIVATE (GNetworkMonitorNetlink) | 
					
						
							|  |  |  |                          G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR, | 
					
						
							|  |  |  |                                                 g_network_monitor_netlink_iface_init) | 
					
						
							|  |  |  |                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, | 
					
						
							|  |  |  |                                                 g_network_monitor_netlink_initable_iface_init) | 
					
						
							|  |  |  |                          _g_io_modules_ensure_extension_points_registered (); | 
					
						
							|  |  |  |                          g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME, | 
					
						
							|  |  |  |                                                          g_define_type_id, | 
					
						
							|  |  |  |                                                          "netlink", | 
					
						
							|  |  |  |                                                          20)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | static void | 
					
						
							|  |  |  | g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-24 15:43:04 +01:00
										 |  |  |   nl->priv = g_network_monitor_netlink_get_instance_private (nl); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | g_network_monitor_netlink_initable_init (GInitable     *initable, | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                                          GCancellable  *cancellable, | 
					
						
							|  |  |  |                                          GError       **error) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | { | 
					
						
							|  |  |  |   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable); | 
					
						
							| 
									
										
										
										
											2012-02-13 21:12:34 -05:00
										 |  |  |   gint sockfd; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   struct sockaddr_nl snl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* We create the socket the old-school way because sockaddr_netlink
 | 
					
						
							|  |  |  |    * can't be represented as a GSocketAddress | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2013-01-22 16:39:49 -05:00
										 |  |  |   sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   if (sockfd == -1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       int errsv = errno; | 
					
						
							|  |  |  |       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                    _("Could not create network monitor: %s"), | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |                    g_strerror (errsv)); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   snl.nl_family = AF_NETLINK; | 
					
						
							|  |  |  |   snl.nl_pid = snl.nl_pad = 0; | 
					
						
							|  |  |  |   snl.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE; | 
					
						
							|  |  |  |   if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       int errsv = errno; | 
					
						
							|  |  |  |       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                    _("Could not create network monitor: %s"), | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |                    g_strerror (errsv)); | 
					
						
							| 
									
										
										
										
											2013-01-25 12:05:26 -05:00
										 |  |  |       (void) g_close (sockfd, NULL); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-13 21:12:34 -05:00
										 |  |  |   nl->priv->sock = g_socket_new_from_fd (sockfd, error); | 
					
						
							| 
									
										
										
										
											2018-09-10 11:58:08 +01:00
										 |  |  |   if (!nl->priv->sock) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-02-13 21:12:34 -05:00
										 |  |  |       g_prefix_error (error, "%s", _("Could not create network monitor: ")); | 
					
						
							| 
									
										
										
										
											2013-01-25 12:05:26 -05:00
										 |  |  |       (void) g_close (sockfd, NULL); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-29 21:18:36 +03:00
										 |  |  | #ifdef SO_PASSCRED
 | 
					
						
							| 
									
										
										
										
											2012-02-13 21:12:34 -05:00
										 |  |  |   if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED, | 
					
						
							|  |  |  | 			    TRUE, NULL)) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-02-13 21:12:34 -05:00
										 |  |  |       int errsv = errno; | 
					
						
							|  |  |  |       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), | 
					
						
							|  |  |  |                    _("Could not create network monitor: %s"), | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |                    g_strerror (errsv)); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-29 21:18:36 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Request the current state */ | 
					
						
							|  |  |  |   if (!request_dump (nl, error)) | 
					
						
							|  |  |  |     return FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* And read responses; since we haven't yet marked the socket
 | 
					
						
							|  |  |  |    * non-blocking, each call will block until a message is received. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   while (nl->priv->dump_networks) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |       GError *local_error = NULL; | 
					
						
							|  |  |  |       if (!read_netlink_messages (nl, &local_error)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           g_warning ("%s", local_error->message); | 
					
						
							|  |  |  |           g_clear_error (&local_error); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_socket_set_blocking (nl->priv->sock, FALSE); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   nl->priv->context = g_main_context_ref_thread_default (); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL); | 
					
						
							|  |  |  |   g_source_set_callback (nl->priv->source, | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |                          (GSourceFunc) read_netlink_messages_callback, nl, NULL); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   g_source_attach (nl->priv->source, nl->priv->context); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 15:27:00 +00:00
										 |  |  |   return initable_parent_iface->init (initable, cancellable, error); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | request_dump (GNetworkMonitorNetlink  *nl, | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |               GError                 **error) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | { | 
					
						
							|  |  |  |   struct nlmsghdr *n; | 
					
						
							|  |  |  |   struct rtgenmsg *gen; | 
					
						
							|  |  |  |   gchar buf[NLMSG_SPACE (sizeof (*gen))]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   memset (buf, 0, sizeof (buf)); | 
					
						
							|  |  |  |   n = (struct nlmsghdr*) buf; | 
					
						
							|  |  |  |   n->nlmsg_len = NLMSG_LENGTH (sizeof (*gen)); | 
					
						
							|  |  |  |   n->nlmsg_type = RTM_GETROUTE; | 
					
						
							|  |  |  |   n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | 
					
						
							|  |  |  |   n->nlmsg_pid = 0; | 
					
						
							|  |  |  |   gen = NLMSG_DATA (n); | 
					
						
							|  |  |  |   gen->rtgen_family = AF_UNSPEC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_socket_send (nl->priv->sock, buf, sizeof (buf), | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                      NULL, error) < 0) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-11-29 21:45:37 +01:00
										 |  |  |       g_prefix_error (error, "%s", _("Could not get network status: ")); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref); | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | timeout_request_dump (gpointer user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GNetworkMonitorNetlink *nl = user_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_source_destroy (nl->priv->dump_source); | 
					
						
							|  |  |  |   g_source_unref (nl->priv->dump_source); | 
					
						
							|  |  |  |   nl->priv->dump_source = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   request_dump (nl, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | queue_request_dump (GNetworkMonitorNetlink *nl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (nl->priv->dump_networks) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nl->priv->dump_source) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_source_destroy (nl->priv->dump_source); | 
					
						
							|  |  |  |       g_source_unref (nl->priv->dump_source); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:49:11 +00:00
										 |  |  |   nl->priv->dump_source = g_timeout_source_new_seconds (1); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   g_source_set_callback (nl->priv->dump_source, | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                          (GSourceFunc) timeout_request_dump, nl, NULL); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   g_source_attach (nl->priv->dump_source, nl->priv->context); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  | static GInetAddressMask * | 
					
						
							|  |  |  | create_inet_address_mask (GSocketFamily  family, | 
					
						
							|  |  |  |                           const guint8  *dest, | 
					
						
							|  |  |  |                           gsize          dest_len) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | { | 
					
						
							|  |  |  |   GInetAddress *dest_addr; | 
					
						
							|  |  |  |   GInetAddressMask *network; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (dest) | 
					
						
							|  |  |  |     dest_addr = g_inet_address_new_from_bytes (dest, family); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     dest_addr = g_inet_address_new_any (family); | 
					
						
							|  |  |  |   network = g_inet_address_mask_new (dest_addr, dest_len, NULL); | 
					
						
							|  |  |  |   g_object_unref (dest_addr); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return network; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | add_network (GNetworkMonitorNetlink *nl, | 
					
						
							|  |  |  |              GSocketFamily           family, | 
					
						
							|  |  |  |              const guint8           *dest, | 
					
						
							|  |  |  |              gsize                   dest_len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   g_return_if_fail (network != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nl->priv->dump_networks) | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |     g_ptr_array_add (nl->priv->dump_networks, g_object_ref (network)); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |     g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_object_unref (network); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | remove_network (GNetworkMonitorNetlink *nl, | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                 GSocketFamily           family, | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |                 const guint8           *dest, | 
					
						
							|  |  |  |                 gsize                   dest_len) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |   GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   g_return_if_fail (network != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nl->priv->dump_networks) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata; | 
					
						
							| 
									
										
										
										
											2020-11-17 11:38:12 +01:00
										 |  |  |       guint i; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       for (i = 0; i < nl->priv->dump_networks->len; i++) | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |           if (g_inet_address_mask_equal (network, dump_networks[i])) | 
					
						
							|  |  |  |             g_ptr_array_remove_index_fast (nl->priv->dump_networks, i--); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |       g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_object_unref (network); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | finish_dump (GNetworkMonitorNetlink *nl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl), | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |                                        (GInetAddressMask **)nl->priv->dump_networks->pdata, | 
					
						
							|  |  |  |                                        nl->priv->dump_networks->len); | 
					
						
							| 
									
										
										
										
											2012-05-17 13:48:21 -04:00
										 |  |  |   g_ptr_array_free (nl->priv->dump_networks, TRUE); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   nl->priv->dump_networks = NULL; | 
					
						
							| 
									
										
										
										
											2025-04-21 22:28:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* FreeBSD features "jailing" functionality, which can be approximated to
 | 
					
						
							|  |  |  |    * Linux namespaces. A jail may or may not share the host's network stack, | 
					
						
							|  |  |  |    * which includes routing tables. | 
					
						
							|  |  |  |    * When jail runs in non-vnet mode and has a shared stack with the host, | 
					
						
							|  |  |  |    * the kernel prevents jailed processes from getting full view on a routing | 
					
						
							|  |  |  |    * table. This makes GNetworkManager believe that we're offline and return | 
					
						
							|  |  |  |    * FALSE for the "available" property. | 
					
						
							|  |  |  |    * To workaround this problem, do the same thing as GNetworkMonitorBase - | 
					
						
							|  |  |  |    * add a fake network of 0 length. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  | #ifdef __FreeBSD__
 | 
					
						
							|  |  |  |   gboolean is_jailed = FALSE; | 
					
						
							|  |  |  |   gsize len = sizeof (is_jailed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sysctlbyname ("security.jail.jailed", &is_jailed, &len, NULL, 0) != 0) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!is_jailed) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (is_jailed && !g_network_monitor_get_network_available (G_NETWORK_MONITOR (nl))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GInetAddressMask *network; | 
					
						
							|  |  |  |       network = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL); | 
					
						
							|  |  |  |       g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network); | 
					
						
							|  |  |  |       g_object_unref (network); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  | read_netlink_messages (GNetworkMonitorNetlink  *nl, | 
					
						
							|  |  |  |                        GError                 **error) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | { | 
					
						
							|  |  |  |   GInputVector iv; | 
					
						
							| 
									
										
										
										
											2011-12-19 15:19:19 -05:00
										 |  |  |   gssize len; | 
					
						
							| 
									
										
										
										
											2015-06-01 10:02:47 +02:00
										 |  |  |   gint flags; | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |   GError *local_error = NULL; | 
					
						
							| 
									
										
										
										
											2016-05-27 07:30:00 +00:00
										 |  |  |   GSocketAddress *addr = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   struct nlmsghdr *msg; | 
					
						
							|  |  |  |   struct rtmsg *rtmsg; | 
					
						
							|  |  |  |   struct rtattr *attr; | 
					
						
							| 
									
										
										
										
											2015-06-01 10:02:47 +02:00
										 |  |  |   struct sockaddr_nl source_sockaddr; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   gsize attrlen; | 
					
						
							| 
									
										
										
										
											2013-06-04 17:29:55 -03:00
										 |  |  |   guint8 *dest, *gateway, *oif; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   iv.buffer = NULL; | 
					
						
							|  |  |  |   iv.size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   flags = MSG_PEEK | MSG_TRUNC; | 
					
						
							|  |  |  |   len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1, | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |                                   NULL, NULL, &flags, NULL, &local_error); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   if (len < 0) | 
					
						
							| 
									
										
										
										
											2024-04-09 16:14:57 +01:00
										 |  |  |     goto done; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   iv.buffer = g_malloc (len); | 
					
						
							|  |  |  |   iv.size = len; | 
					
						
							| 
									
										
										
										
											2015-06-01 10:02:47 +02:00
										 |  |  |   len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1, | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |                                   NULL, NULL, NULL, NULL, &local_error); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   if (len < 0) | 
					
						
							| 
									
										
										
										
											2024-04-09 16:14:57 +01:00
										 |  |  |     goto done; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |   if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &local_error)) | 
					
						
							| 
									
										
										
										
											2024-04-09 16:14:57 +01:00
										 |  |  |     goto done; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 10:02:47 +02:00
										 |  |  |   /* If the sender port id is 0 (not fakeable) then the message is from the kernel */ | 
					
						
							|  |  |  |   if (source_sockaddr.nl_pid != 0) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   msg = (struct nlmsghdr *) iv.buffer; | 
					
						
							|  |  |  |   for (; len > 0; msg = NLMSG_NEXT (msg, len)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (!NLMSG_OK (msg, (size_t) len)) | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |           g_set_error_literal (&local_error, | 
					
						
							|  |  |  |                                G_IO_ERROR, | 
					
						
							|  |  |  |                                G_IO_ERROR_PARTIAL_INPUT, | 
					
						
							|  |  |  |                                "netlink message was truncated; shouldn't happen..."); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |           goto done; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       switch (msg->nlmsg_type) | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |         case RTM_NEWROUTE: | 
					
						
							|  |  |  |         case RTM_DELROUTE: | 
					
						
							|  |  |  |           rtmsg = NLMSG_DATA (msg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           if (rtmsg->rtm_type == RTN_UNREACHABLE) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg)); | 
					
						
							|  |  |  |           attr = RTM_RTA (rtmsg); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:29:55 -03:00
										 |  |  |           dest = gateway = oif = NULL; | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |           while (RTA_OK (attr, attrlen)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               if (attr->rta_type == RTA_DST) | 
					
						
							|  |  |  |                 dest = RTA_DATA (attr); | 
					
						
							|  |  |  |               else if (attr->rta_type == RTA_GATEWAY) | 
					
						
							|  |  |  |                 gateway = RTA_DATA (attr); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:29:55 -03:00
										 |  |  |               else if (attr->rta_type == RTA_OIF) | 
					
						
							|  |  |  |                 oif = RTA_DATA (attr); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |               attr = RTA_NEXT (attr, attrlen); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-04 17:29:55 -03:00
										 |  |  |           if (dest || gateway || oif) | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2014-01-28 14:46:37 -05:00
										 |  |  |               /* Unless we're processing the results of a dump, ignore
 | 
					
						
							|  |  |  |                * IPv6 link-local multicast routes, which are added and | 
					
						
							|  |  |  |                * removed all the time for some reason. | 
					
						
							|  |  |  |                */ | 
					
						
							| 
									
										
										
										
											2014-03-26 19:45:52 -04:00
										 |  |  | #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a)           \
 | 
					
						
							|  |  |  |               ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-28 14:46:37 -05:00
										 |  |  |               if (!nl->priv->dump_networks && | 
					
						
							|  |  |  |                   rtmsg->rtm_family == AF_INET6 && | 
					
						
							|  |  |  |                   rtmsg->rtm_dst_len != 0 && | 
					
						
							| 
									
										
										
										
											2019-08-19 23:10:23 +02:00
										 |  |  |                   (dest && UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest))) | 
					
						
							| 
									
										
										
										
											2014-01-28 14:46:37 -05:00
										 |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |               if (msg->nlmsg_type == RTM_NEWROUTE) | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |                 add_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |               else | 
					
						
							| 
									
										
										
										
											2018-02-27 12:51:16 +00:00
										 |  |  |                 remove_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |               queue_request_dump (nl); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case NLMSG_DONE: | 
					
						
							|  |  |  |           finish_dump (nl); | 
					
						
							|  |  |  |           goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case NLMSG_ERROR: | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             struct nlmsgerr *e = NLMSG_DATA (msg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |             g_set_error (&local_error, | 
					
						
							|  |  |  |                          G_IO_ERROR, | 
					
						
							|  |  |  |                          g_io_error_from_errno (-e->error), | 
					
						
							|  |  |  |                          "netlink error: %s", | 
					
						
							|  |  |  |                          g_strerror (-e->error)); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |           } | 
					
						
							|  |  |  |           goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  |           g_set_error (&local_error, | 
					
						
							|  |  |  |                        G_IO_ERROR, | 
					
						
							|  |  |  |                        G_IO_ERROR_INVALID_DATA, | 
					
						
							|  |  |  |                        "unexpected netlink message %d", | 
					
						
							|  |  |  |                        msg->nlmsg_type); | 
					
						
							| 
									
										
										
										
											2011-12-10 21:46:13 -05:00
										 |  |  |           goto done; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  done: | 
					
						
							|  |  |  |   g_free (iv.buffer); | 
					
						
							| 
									
										
										
										
											2016-05-27 07:30:00 +00:00
										 |  |  |   g_clear_object (&addr); | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-09 16:14:57 +01:00
										 |  |  |   if (local_error != NULL && nl->priv->dump_networks) | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |     finish_dump (nl); | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-09 16:14:57 +01:00
										 |  |  |   if (local_error != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_propagate_prefixed_error (error, local_error, "Error on netlink socket: "); | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_network_monitor_netlink_finalize (GObject *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nl->priv->source) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_source_destroy (nl->priv->source); | 
					
						
							|  |  |  |       g_source_unref (nl->priv->source); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nl->priv->dump_source) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_source_destroy (nl->priv->dump_source); | 
					
						
							|  |  |  |       g_source_unref (nl->priv->dump_source); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 12:00:46 +01:00
										 |  |  |   if (nl->priv->sock) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_socket_close (nl->priv->sock, NULL); | 
					
						
							|  |  |  |       g_object_unref (nl->priv->sock); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   g_clear_pointer (&nl->priv->context, g_main_context_unref); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:52:39 +00:00
										 |  |  |   g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref); | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 12:07:48 +01:00
										 |  |  | static gboolean | 
					
						
							|  |  |  | read_netlink_messages_callback (GSocket      *socket, | 
					
						
							|  |  |  |                                 GIOCondition  condition, | 
					
						
							|  |  |  |                                 gpointer      user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GError *error = NULL; | 
					
						
							|  |  |  |   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (user_data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!read_netlink_messages (nl, &error)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_warning ("Error reading netlink message: %s", error->message); | 
					
						
							|  |  |  |       g_clear_error (&error); | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | static void | 
					
						
							|  |  |  | g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 12:48:05 +00:00
										 |  |  |   gobject_class->finalize = g_network_monitor_netlink_finalize; | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_network_monitor_netlink_initable_iface_init (GInitableIface *iface) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-04-10 15:27:00 +00:00
										 |  |  |   initable_parent_iface = g_type_interface_peek_parent (iface); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-12 15:59:36 -04:00
										 |  |  |   iface->init = g_network_monitor_netlink_initable_init; | 
					
						
							|  |  |  | } |