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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
27 #include "gnetworkmonitornetlink.h"
28 #include "gcredentials.h"
29 #include "ginetaddressmask.h"
30 #include "ginitable.h"
31 #include "giomodule-priv.h"
33 #include "glib/gstdio.h"
34 #include "gnetworkingprivate.h"
35 #include "gnetworkmonitor.h"
37 #include "gunixcredentialsmessage.h"
39 /* must come at the end to pick system includes from
40 * gnetworkingprivate.h */
41 #include <linux/netlink.h>
42 #include <linux/rtnetlink.h>
44 static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*iface
);
45 static void g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
);
47 struct _GNetworkMonitorNetlinkPrivate
50 GSource
*source
, *dump_source
;
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
);
82 g_network_monitor_netlink_initable_init (GInitable
*initable
,
83 GCancellable
*cancellable
,
86 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (initable
);
88 struct sockaddr_nl snl
;
90 /* We create the socket the old-school way because sockaddr_netlink
91 * can't be represented as a GSocketAddress
93 sockfd
= g_socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
, NULL
);
97 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
98 _("Could not create network monitor: %s"),
103 snl
.nl_family
= AF_NETLINK
;
104 snl
.nl_pid
= snl
.nl_pad
= 0;
105 snl
.nl_groups
= RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_ROUTE
;
106 if (bind (sockfd
, (struct sockaddr
*)&snl
, sizeof (snl
)) != 0)
109 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
110 _("Could not create network monitor: %s"),
112 (void) g_close (sockfd
, NULL
);
116 nl
->priv
->sock
= g_socket_new_from_fd (sockfd
, error
);
119 g_prefix_error (error
, "%s", _("Could not create network monitor: "));
120 (void) g_close (sockfd
, NULL
);
124 if (!g_socket_set_option (nl
->priv
->sock
, SOL_SOCKET
, SO_PASSCRED
,
128 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
129 _("Could not create network monitor: %s"),
134 /* Request the current state */
135 if (!request_dump (nl
, error
))
138 /* And read responses; since we haven't yet marked the socket
139 * non-blocking, each call will block until a message is received.
141 while (nl
->priv
->dump_networks
)
143 if (!read_netlink_messages (NULL
, G_IO_IN
, nl
))
147 g_socket_set_blocking (nl
->priv
->sock
, FALSE
);
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
,
152 g_main_context_get_thread_default ());
158 request_dump (GNetworkMonitorNetlink
*nl
,
162 struct rtgenmsg
*gen
;
163 gchar buf
[NLMSG_SPACE (sizeof (*gen
))];
165 memset (buf
, 0, sizeof (buf
));
166 n
= (struct nlmsghdr
*) buf
;
167 n
->nlmsg_len
= NLMSG_LENGTH (sizeof (*gen
));
168 n
->nlmsg_type
= RTM_GETROUTE
;
169 n
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
;
171 gen
= NLMSG_DATA (n
);
172 gen
->rtgen_family
= AF_UNSPEC
;
174 if (g_socket_send (nl
->priv
->sock
, buf
, sizeof (buf
),
177 g_prefix_error (error
, "%s", _("Could not get network status: "));
181 nl
->priv
->dump_networks
= g_ptr_array_new_with_free_func (g_object_unref
);
186 timeout_request_dump (gpointer user_data
)
188 GNetworkMonitorNetlink
*nl
= user_data
;
190 g_source_destroy (nl
->priv
->dump_source
);
191 g_source_unref (nl
->priv
->dump_source
);
192 nl
->priv
->dump_source
= NULL
;
194 request_dump (nl
, NULL
);
200 queue_request_dump (GNetworkMonitorNetlink
*nl
)
202 if (nl
->priv
->dump_networks
)
205 if (nl
->priv
->dump_source
)
207 g_source_destroy (nl
->priv
->dump_source
);
208 g_source_unref (nl
->priv
->dump_source
);
211 nl
->priv
->dump_source
= g_timeout_source_new (1000);
212 g_source_set_callback (nl
->priv
->dump_source
,
213 (GSourceFunc
) timeout_request_dump
, nl
, NULL
);
214 g_source_attach (nl
->priv
->dump_source
,
215 g_main_context_get_thread_default ());
219 add_network (GNetworkMonitorNetlink
*nl
,
220 GSocketFamily family
,
224 GInetAddress
*dest_addr
;
225 GInetAddressMask
*network
;
228 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
230 dest_addr
= g_inet_address_new_any (family
);
231 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
232 g_object_unref (dest_addr
);
233 g_return_if_fail (network
!= NULL
);
235 if (nl
->priv
->dump_networks
)
236 g_ptr_array_add (nl
->priv
->dump_networks
, network
);
239 g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl
), network
);
240 g_object_unref (network
);
245 remove_network (GNetworkMonitorNetlink
*nl
,
246 GSocketFamily family
,
250 GInetAddress
*dest_addr
;
251 GInetAddressMask
*network
;
254 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
256 dest_addr
= g_inet_address_new_any (family
);
257 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
258 g_object_unref (dest_addr
);
259 g_return_if_fail (network
!= NULL
);
261 if (nl
->priv
->dump_networks
)
263 GInetAddressMask
**dump_networks
= (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
;
266 for (i
= 0; i
< nl
->priv
->dump_networks
->len
; i
++)
268 if (g_inet_address_mask_equal (network
, dump_networks
[i
]))
269 g_ptr_array_remove_index_fast (nl
->priv
->dump_networks
, i
--);
271 g_object_unref (network
);
275 g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl
), network
);
276 g_object_unref (network
);
281 finish_dump (GNetworkMonitorNetlink
*nl
)
283 g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl
),
284 (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
,
285 nl
->priv
->dump_networks
->len
);
286 g_ptr_array_free (nl
->priv
->dump_networks
, TRUE
);
287 nl
->priv
->dump_networks
= NULL
;
291 read_netlink_messages (GSocket
*socket
,
292 GIOCondition condition
,
295 GNetworkMonitorNetlink
*nl
= user_data
;
298 GSocketControlMessage
**cmsgs
= NULL
;
299 gint num_cmsgs
= 0, i
, flags
;
300 GError
*error
= NULL
;
303 struct nlmsghdr
*msg
;
307 guint8
*dest
, *gateway
, *oif
;
308 gboolean retval
= TRUE
;
313 flags
= MSG_PEEK
| MSG_TRUNC
;
314 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
315 NULL
, NULL
, &flags
, NULL
, &error
);
318 g_warning ("Error on netlink socket: %s", error
->message
);
319 g_error_free (error
);
320 if (nl
->priv
->dump_networks
)
325 iv
.buffer
= g_malloc (len
);
327 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
328 &cmsgs
, &num_cmsgs
, NULL
, NULL
, &error
);
331 g_warning ("Error on netlink socket: %s", error
->message
);
332 g_error_free (error
);
333 if (nl
->priv
->dump_networks
)
338 if (num_cmsgs
!= 1 || !G_IS_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]))
341 creds
= g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]));
342 sender
= g_credentials_get_unix_user (creds
, NULL
);
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 if (msg
->nlmsg_type
== RTM_NEWROUTE
)
384 add_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
);
386 remove_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
);
387 queue_request_dump (nl
);
397 struct nlmsgerr
*e
= NLMSG_DATA (msg
);
399 g_warning ("netlink error: %s", g_strerror (-e
->error
));
405 g_warning ("unexpected netlink message %d", msg
->nlmsg_type
);
412 for (i
= 0; i
< num_cmsgs
; i
++)
413 g_object_unref (cmsgs
[i
]);
418 if (!retval
&& nl
->priv
->dump_networks
)
424 g_network_monitor_netlink_finalize (GObject
*object
)
426 GNetworkMonitorNetlink
*nl
= G_NETWORK_MONITOR_NETLINK (object
);
430 g_socket_close (nl
->priv
->sock
, NULL
);
431 g_object_unref (nl
->priv
->sock
);
434 if (nl
->priv
->source
)
436 g_source_destroy (nl
->priv
->source
);
437 g_source_unref (nl
->priv
->source
);
440 if (nl
->priv
->dump_source
)
442 g_source_destroy (nl
->priv
->dump_source
);
443 g_source_unref (nl
->priv
->dump_source
);
446 G_OBJECT_CLASS (g_network_monitor_netlink_parent_class
)->finalize (object
);
450 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass
*nl_class
)
452 GObjectClass
*gobject_class
= G_OBJECT_CLASS (nl_class
);
454 gobject_class
->finalize
= g_network_monitor_netlink_finalize
;
458 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*monitor_iface
)
463 g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
)
465 iface
->init
= g_network_monitor_netlink_initable_init
;