1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2011 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include "gnetworkmonitornetlink.h"
26 #include "gcredentials.h"
27 #include "ginetaddressmask.h"
28 #include "ginitable.h"
29 #include "giomodule-priv.h"
31 #include "glib/gstdio.h"
32 #include "gnetworkingprivate.h"
33 #include "gnetworkmonitor.h"
35 #include "gunixcredentialsmessage.h"
37 /* must come at the end to pick system includes from
38 * gnetworkingprivate.h */
39 #include <linux/netlink.h>
40 #include <linux/rtnetlink.h>
42 static GInitableIface
*initable_parent_iface
;
43 static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*iface
);
44 static void g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
);
46 struct _GNetworkMonitorNetlinkPrivate
49 GSource
*source
, *dump_source
;
50 GMainContext
*context
;
52 GPtrArray
*dump_networks
;
55 static gboolean
read_netlink_messages (GSocket
*socket
,
56 GIOCondition condition
,
58 static gboolean
request_dump (GNetworkMonitorNetlink
*nl
,
61 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
62 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink
, g_network_monitor_netlink
, G_TYPE_NETWORK_MONITOR_BASE
,
63 G_ADD_PRIVATE (GNetworkMonitorNetlink
)
64 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR
,
65 g_network_monitor_netlink_iface_init
)
66 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
67 g_network_monitor_netlink_initable_iface_init
)
68 _g_io_modules_ensure_extension_points_registered ();
69 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME
,
75 g_network_monitor_netlink_init (GNetworkMonitorNetlink
*nl
)
77 nl
->priv
= g_network_monitor_netlink_get_instance_private (nl
);
81 g_network_monitor_netlink_initable_init (GInitable
*initable
,
82 GCancellable
*cancellable
,
85 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (initable
);
87 struct sockaddr_nl snl
;
89 /* We create the socket the old-school way because sockaddr_netlink
90 * can't be represented as a GSocketAddress
92 sockfd
= g_socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
, NULL
);
96 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
97 _("Could not create network monitor: %s"),
102 snl
.nl_family
= AF_NETLINK
;
103 snl
.nl_pid
= snl
.nl_pad
= 0;
104 snl
.nl_groups
= RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_ROUTE
;
105 if (bind (sockfd
, (struct sockaddr
*)&snl
, sizeof (snl
)) != 0)
108 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
109 _("Could not create network monitor: %s"),
111 (void) g_close (sockfd
, NULL
);
115 nl
->priv
->sock
= g_socket_new_from_fd (sockfd
, error
);
118 g_prefix_error (error
, "%s", _("Could not create network monitor: "));
119 (void) g_close (sockfd
, NULL
);
123 if (!g_socket_set_option (nl
->priv
->sock
, SOL_SOCKET
, SO_PASSCRED
,
127 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
128 _("Could not create network monitor: %s"),
133 /* Request the current state */
134 if (!request_dump (nl
, error
))
137 /* And read responses; since we haven't yet marked the socket
138 * non-blocking, each call will block until a message is received.
140 while (nl
->priv
->dump_networks
)
142 if (!read_netlink_messages (NULL
, G_IO_IN
, nl
))
146 g_socket_set_blocking (nl
->priv
->sock
, FALSE
);
147 nl
->priv
->context
= g_main_context_ref_thread_default ();
148 nl
->priv
->source
= g_socket_create_source (nl
->priv
->sock
, G_IO_IN
, NULL
);
149 g_source_set_callback (nl
->priv
->source
,
150 (GSourceFunc
) read_netlink_messages
, nl
, NULL
);
151 g_source_attach (nl
->priv
->source
, nl
->priv
->context
);
153 return initable_parent_iface
->init (initable
, cancellable
, error
);
157 request_dump (GNetworkMonitorNetlink
*nl
,
161 struct rtgenmsg
*gen
;
162 gchar buf
[NLMSG_SPACE (sizeof (*gen
))];
164 memset (buf
, 0, sizeof (buf
));
165 n
= (struct nlmsghdr
*) buf
;
166 n
->nlmsg_len
= NLMSG_LENGTH (sizeof (*gen
));
167 n
->nlmsg_type
= RTM_GETROUTE
;
168 n
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
;
170 gen
= NLMSG_DATA (n
);
171 gen
->rtgen_family
= AF_UNSPEC
;
173 if (g_socket_send (nl
->priv
->sock
, buf
, sizeof (buf
),
176 g_prefix_error (error
, "%s", _("Could not get network status: "));
180 nl
->priv
->dump_networks
= g_ptr_array_new_with_free_func (g_object_unref
);
185 timeout_request_dump (gpointer user_data
)
187 GNetworkMonitorNetlink
*nl
= user_data
;
189 g_source_destroy (nl
->priv
->dump_source
);
190 g_source_unref (nl
->priv
->dump_source
);
191 nl
->priv
->dump_source
= NULL
;
193 request_dump (nl
, NULL
);
199 queue_request_dump (GNetworkMonitorNetlink
*nl
)
201 if (nl
->priv
->dump_networks
)
204 if (nl
->priv
->dump_source
)
206 g_source_destroy (nl
->priv
->dump_source
);
207 g_source_unref (nl
->priv
->dump_source
);
210 nl
->priv
->dump_source
= g_timeout_source_new_seconds (1);
211 g_source_set_callback (nl
->priv
->dump_source
,
212 (GSourceFunc
) timeout_request_dump
, nl
, NULL
);
213 g_source_attach (nl
->priv
->dump_source
, nl
->priv
->context
);
216 static GInetAddressMask
*
217 create_inet_address_mask (GSocketFamily family
,
221 GInetAddress
*dest_addr
;
222 GInetAddressMask
*network
;
225 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
227 dest_addr
= g_inet_address_new_any (family
);
228 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
229 g_object_unref (dest_addr
);
235 add_network (GNetworkMonitorNetlink
*nl
,
236 GSocketFamily family
,
240 GInetAddressMask
*network
= create_inet_address_mask (family
, dest
, dest_len
);
241 g_return_if_fail (network
!= NULL
);
243 if (nl
->priv
->dump_networks
)
244 g_ptr_array_add (nl
->priv
->dump_networks
, g_object_ref (network
));
246 g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl
), network
);
248 g_object_unref (network
);
252 remove_network (GNetworkMonitorNetlink
*nl
,
253 GSocketFamily family
,
257 GInetAddressMask
*network
= create_inet_address_mask (family
, dest
, dest_len
);
258 g_return_if_fail (network
!= NULL
);
260 if (nl
->priv
->dump_networks
)
262 GInetAddressMask
**dump_networks
= (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
;
265 for (i
= 0; i
< nl
->priv
->dump_networks
->len
; i
++)
267 if (g_inet_address_mask_equal (network
, dump_networks
[i
]))
268 g_ptr_array_remove_index_fast (nl
->priv
->dump_networks
, i
--);
273 g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl
), network
);
276 g_object_unref (network
);
280 finish_dump (GNetworkMonitorNetlink
*nl
)
282 g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl
),
283 (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
,
284 nl
->priv
->dump_networks
->len
);
285 g_ptr_array_free (nl
->priv
->dump_networks
, TRUE
);
286 nl
->priv
->dump_networks
= NULL
;
290 read_netlink_messages (GSocket
*socket
,
291 GIOCondition condition
,
294 GNetworkMonitorNetlink
*nl
= user_data
;
298 GError
*error
= NULL
;
299 GSocketAddress
*addr
= NULL
;
300 struct nlmsghdr
*msg
;
303 struct sockaddr_nl source_sockaddr
;
305 guint8
*dest
, *gateway
, *oif
;
306 gboolean retval
= TRUE
;
311 flags
= MSG_PEEK
| MSG_TRUNC
;
312 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
313 NULL
, NULL
, &flags
, NULL
, &error
);
316 g_warning ("Error on netlink socket: %s", error
->message
);
317 g_clear_error (&error
);
322 iv
.buffer
= g_malloc (len
);
324 len
= g_socket_receive_message (nl
->priv
->sock
, &addr
, &iv
, 1,
325 NULL
, NULL
, NULL
, NULL
, &error
);
328 g_warning ("Error on netlink socket: %s", error
->message
);
329 g_clear_error (&error
);
334 if (!g_socket_address_to_native (addr
, &source_sockaddr
, sizeof (source_sockaddr
), &error
))
336 g_warning ("Error on netlink socket: %s", error
->message
);
337 g_clear_error (&error
);
342 /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
343 if (source_sockaddr
.nl_pid
!= 0)
346 msg
= (struct nlmsghdr
*) iv
.buffer
;
347 for (; len
> 0; msg
= NLMSG_NEXT (msg
, len
))
349 if (!NLMSG_OK (msg
, (size_t) len
))
351 g_warning ("netlink message was truncated; shouldn't happen...");
356 switch (msg
->nlmsg_type
)
360 rtmsg
= NLMSG_DATA (msg
);
362 if (rtmsg
->rtm_family
!= AF_INET
&& rtmsg
->rtm_family
!= AF_INET6
)
364 if (rtmsg
->rtm_type
== RTN_UNREACHABLE
)
367 attrlen
= NLMSG_PAYLOAD (msg
, sizeof (struct rtmsg
));
368 attr
= RTM_RTA (rtmsg
);
369 dest
= gateway
= oif
= NULL
;
370 while (RTA_OK (attr
, attrlen
))
372 if (attr
->rta_type
== RTA_DST
)
373 dest
= RTA_DATA (attr
);
374 else if (attr
->rta_type
== RTA_GATEWAY
)
375 gateway
= RTA_DATA (attr
);
376 else if (attr
->rta_type
== RTA_OIF
)
377 oif
= RTA_DATA (attr
);
378 attr
= RTA_NEXT (attr
, attrlen
);
381 if (dest
|| gateway
|| oif
)
383 /* Unless we're processing the results of a dump, ignore
384 * IPv6 link-local multicast routes, which are added and
385 * removed all the time for some reason.
387 #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a) \
388 ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
390 if (!nl
->priv
->dump_networks
&&
391 rtmsg
->rtm_family
== AF_INET6
&&
392 rtmsg
->rtm_dst_len
!= 0 &&
393 UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest
))
396 if (msg
->nlmsg_type
== RTM_NEWROUTE
)
397 add_network (nl
, rtmsg
->rtm_family
, dest
, rtmsg
->rtm_dst_len
);
399 remove_network (nl
, rtmsg
->rtm_family
, dest
, rtmsg
->rtm_dst_len
);
400 queue_request_dump (nl
);
410 struct nlmsgerr
*e
= NLMSG_DATA (msg
);
412 g_warning ("netlink error: %s", g_strerror (-e
->error
));
418 g_warning ("unexpected netlink message %d", msg
->nlmsg_type
);
426 g_clear_object (&addr
);
428 if (!retval
&& nl
->priv
->dump_networks
)
434 g_network_monitor_netlink_finalize (GObject
*object
)
436 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (object
);
440 g_socket_close (nl
->priv
->sock
, NULL
);
441 g_object_unref (nl
->priv
->sock
);
444 if (nl
->priv
->source
)
446 g_source_destroy (nl
->priv
->source
);
447 g_source_unref (nl
->priv
->source
);
450 if (nl
->priv
->dump_source
)
452 g_source_destroy (nl
->priv
->dump_source
);
453 g_source_unref (nl
->priv
->dump_source
);
456 g_clear_pointer (&nl
->priv
->context
, g_main_context_unref
);
457 g_clear_pointer (&nl
->priv
->dump_networks
, g_ptr_array_unref
);
459 G_OBJECT_CLASS (g_network_monitor_netlink_parent_class
)->finalize (object
);
463 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass
*nl_class
)
465 GObjectClass
*gobject_class
= G_OBJECT_CLASS (nl_class
);
467 gobject_class
->finalize
= g_network_monitor_netlink_finalize
;
471 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*monitor_iface
)
476 g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
)
478 initable_parent_iface
= g_type_interface_peek_parent (iface
);
480 iface
->init
= g_network_monitor_netlink_initable_init
;