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 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 void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*iface
);
43 static void g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
);
45 struct _GNetworkMonitorNetlinkPrivate
48 GSource
*source
, *dump_source
;
50 GPtrArray
*dump_networks
;
53 static gboolean
read_netlink_messages (GSocket
*socket
,
54 GIOCondition condition
,
56 static gboolean
request_dump (GNetworkMonitorNetlink
*nl
,
59 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
60 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink
, g_network_monitor_netlink
, G_TYPE_NETWORK_MONITOR_BASE
,
61 G_ADD_PRIVATE (GNetworkMonitorNetlink
)
62 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR
,
63 g_network_monitor_netlink_iface_init
)
64 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
65 g_network_monitor_netlink_initable_iface_init
)
66 _g_io_modules_ensure_extension_points_registered ();
67 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME
,
73 g_network_monitor_netlink_init (GNetworkMonitorNetlink
*nl
)
75 nl
->priv
= g_network_monitor_netlink_get_instance_private (nl
);
80 g_network_monitor_netlink_initable_init (GInitable
*initable
,
81 GCancellable
*cancellable
,
84 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (initable
);
86 struct sockaddr_nl snl
;
88 /* We create the socket the old-school way because sockaddr_netlink
89 * can't be represented as a GSocketAddress
91 sockfd
= g_socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
, NULL
);
95 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
96 _("Could not create network monitor: %s"),
101 snl
.nl_family
= AF_NETLINK
;
102 snl
.nl_pid
= snl
.nl_pad
= 0;
103 snl
.nl_groups
= RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_ROUTE
;
104 if (bind (sockfd
, (struct sockaddr
*)&snl
, sizeof (snl
)) != 0)
107 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
108 _("Could not create network monitor: %s"),
110 (void) g_close (sockfd
, NULL
);
114 nl
->priv
->sock
= g_socket_new_from_fd (sockfd
, error
);
117 g_prefix_error (error
, "%s", _("Could not create network monitor: "));
118 (void) g_close (sockfd
, NULL
);
122 if (!g_socket_set_option (nl
->priv
->sock
, SOL_SOCKET
, SO_PASSCRED
,
126 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
127 _("Could not create network monitor: %s"),
132 /* Request the current state */
133 if (!request_dump (nl
, error
))
136 /* And read responses; since we haven't yet marked the socket
137 * non-blocking, each call will block until a message is received.
139 while (nl
->priv
->dump_networks
)
141 if (!read_netlink_messages (NULL
, G_IO_IN
, nl
))
145 g_socket_set_blocking (nl
->priv
->sock
, FALSE
);
146 nl
->priv
->source
= g_socket_create_source (nl
->priv
->sock
, G_IO_IN
, NULL
);
147 g_source_set_callback (nl
->priv
->source
,
148 (GSourceFunc
) read_netlink_messages
, nl
, NULL
);
149 g_source_attach (nl
->priv
->source
,
150 g_main_context_get_thread_default ());
156 request_dump (GNetworkMonitorNetlink
*nl
,
160 struct rtgenmsg
*gen
;
161 gchar buf
[NLMSG_SPACE (sizeof (*gen
))];
163 memset (buf
, 0, sizeof (buf
));
164 n
= (struct nlmsghdr
*) buf
;
165 n
->nlmsg_len
= NLMSG_LENGTH (sizeof (*gen
));
166 n
->nlmsg_type
= RTM_GETROUTE
;
167 n
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
;
169 gen
= NLMSG_DATA (n
);
170 gen
->rtgen_family
= AF_UNSPEC
;
172 if (g_socket_send (nl
->priv
->sock
, buf
, sizeof (buf
),
175 g_prefix_error (error
, "%s", _("Could not get network status: "));
179 nl
->priv
->dump_networks
= g_ptr_array_new_with_free_func (g_object_unref
);
184 timeout_request_dump (gpointer user_data
)
186 GNetworkMonitorNetlink
*nl
= user_data
;
188 g_source_destroy (nl
->priv
->dump_source
);
189 g_source_unref (nl
->priv
->dump_source
);
190 nl
->priv
->dump_source
= NULL
;
192 request_dump (nl
, NULL
);
198 queue_request_dump (GNetworkMonitorNetlink
*nl
)
200 if (nl
->priv
->dump_networks
)
203 if (nl
->priv
->dump_source
)
205 g_source_destroy (nl
->priv
->dump_source
);
206 g_source_unref (nl
->priv
->dump_source
);
209 nl
->priv
->dump_source
= g_timeout_source_new (1000);
210 g_source_set_callback (nl
->priv
->dump_source
,
211 (GSourceFunc
) timeout_request_dump
, nl
, NULL
);
212 g_source_attach (nl
->priv
->dump_source
,
213 g_main_context_get_thread_default ());
217 add_network (GNetworkMonitorNetlink
*nl
,
218 GSocketFamily family
,
222 GInetAddress
*dest_addr
;
223 GInetAddressMask
*network
;
226 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
228 dest_addr
= g_inet_address_new_any (family
);
229 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
230 g_object_unref (dest_addr
);
231 g_return_if_fail (network
!= NULL
);
233 if (nl
->priv
->dump_networks
)
234 g_ptr_array_add (nl
->priv
->dump_networks
, network
);
237 g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl
), network
);
238 g_object_unref (network
);
243 remove_network (GNetworkMonitorNetlink
*nl
,
244 GSocketFamily family
,
248 GInetAddress
*dest_addr
;
249 GInetAddressMask
*network
;
252 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
254 dest_addr
= g_inet_address_new_any (family
);
255 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
256 g_object_unref (dest_addr
);
257 g_return_if_fail (network
!= NULL
);
259 if (nl
->priv
->dump_networks
)
261 GInetAddressMask
**dump_networks
= (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
;
264 for (i
= 0; i
< nl
->priv
->dump_networks
->len
; i
++)
266 if (g_inet_address_mask_equal (network
, dump_networks
[i
]))
267 g_ptr_array_remove_index_fast (nl
->priv
->dump_networks
, i
--);
269 g_object_unref (network
);
273 g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl
), network
);
274 g_object_unref (network
);
279 finish_dump (GNetworkMonitorNetlink
*nl
)
281 g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl
),
282 (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
,
283 nl
->priv
->dump_networks
->len
);
284 g_ptr_array_free (nl
->priv
->dump_networks
, TRUE
);
285 nl
->priv
->dump_networks
= NULL
;
289 read_netlink_messages (GSocket
*socket
,
290 GIOCondition condition
,
293 GNetworkMonitorNetlink
*nl
= user_data
;
296 GSocketControlMessage
**cmsgs
= NULL
;
297 gint num_cmsgs
= 0, i
, flags
;
298 GError
*error
= NULL
;
301 struct nlmsghdr
*msg
;
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_error_free (error
);
318 if (nl
->priv
->dump_networks
)
323 iv
.buffer
= g_malloc (len
);
325 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
326 &cmsgs
, &num_cmsgs
, NULL
, NULL
, &error
);
329 g_warning ("Error on netlink socket: %s", error
->message
);
330 g_error_free (error
);
331 if (nl
->priv
->dump_networks
)
336 if (num_cmsgs
!= 1 || !G_IS_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]))
339 creds
= g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]));
340 sender
= g_credentials_get_unix_user (creds
, NULL
);
344 msg
= (struct nlmsghdr
*) iv
.buffer
;
345 for (; len
> 0; msg
= NLMSG_NEXT (msg
, len
))
347 if (!NLMSG_OK (msg
, (size_t) len
))
349 g_warning ("netlink message was truncated; shouldn't happen...");
354 switch (msg
->nlmsg_type
)
358 rtmsg
= NLMSG_DATA (msg
);
360 if (rtmsg
->rtm_family
!= AF_INET
&& rtmsg
->rtm_family
!= AF_INET6
)
362 if (rtmsg
->rtm_type
== RTN_UNREACHABLE
)
365 attrlen
= NLMSG_PAYLOAD (msg
, sizeof (struct rtmsg
));
366 attr
= RTM_RTA (rtmsg
);
367 dest
= gateway
= oif
= NULL
;
368 while (RTA_OK (attr
, attrlen
))
370 if (attr
->rta_type
== RTA_DST
)
371 dest
= RTA_DATA (attr
);
372 else if (attr
->rta_type
== RTA_GATEWAY
)
373 gateway
= RTA_DATA (attr
);
374 else if (attr
->rta_type
== RTA_OIF
)
375 oif
= RTA_DATA (attr
);
376 attr
= RTA_NEXT (attr
, attrlen
);
379 if (dest
|| gateway
|| oif
)
381 /* Unless we're processing the results of a dump, ignore
382 * IPv6 link-local multicast routes, which are added and
383 * removed all the time for some reason.
385 #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a) \
386 ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
388 if (!nl
->priv
->dump_networks
&&
389 rtmsg
->rtm_family
== AF_INET6
&&
390 rtmsg
->rtm_dst_len
!= 0 &&
391 UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest
))
394 if (msg
->nlmsg_type
== RTM_NEWROUTE
)
395 add_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
);
397 remove_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
);
398 queue_request_dump (nl
);
408 struct nlmsgerr
*e
= NLMSG_DATA (msg
);
410 g_warning ("netlink error: %s", g_strerror (-e
->error
));
416 g_warning ("unexpected netlink message %d", msg
->nlmsg_type
);
423 for (i
= 0; i
< num_cmsgs
; i
++)
424 g_object_unref (cmsgs
[i
]);
429 if (!retval
&& nl
->priv
->dump_networks
)
435 g_network_monitor_netlink_finalize (GObject
*object
)
437 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (object
);
441 g_socket_close (nl
->priv
->sock
, NULL
);
442 g_object_unref (nl
->priv
->sock
);
445 if (nl
->priv
->source
)
447 g_source_destroy (nl
->priv
->source
);
448 g_source_unref (nl
->priv
->source
);
451 if (nl
->priv
->dump_source
)
453 g_source_destroy (nl
->priv
->dump_source
);
454 g_source_unref (nl
->priv
->dump_source
);
457 G_OBJECT_CLASS (g_network_monitor_netlink_parent_class
)->finalize (object
);
461 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass
*nl_class
)
463 GObjectClass
*gobject_class
= G_OBJECT_CLASS (nl_class
);
465 gobject_class
->finalize
= g_network_monitor_netlink_finalize
;
469 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*monitor_iface
)
474 g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
)
476 iface
->init
= g_network_monitor_netlink_initable_init
;