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.
26 #include "gnetworkmonitornetlink.h"
27 #include "gcredentials.h"
28 #include "ginetaddressmask.h"
29 #include "ginitable.h"
30 #include "giomodule-priv.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 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
46 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink
, g_network_monitor_netlink
, G_TYPE_NETWORK_MONITOR_BASE
,
47 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR
,
48 g_network_monitor_netlink_iface_init
)
49 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
50 g_network_monitor_netlink_initable_iface_init
)
51 _g_io_modules_ensure_extension_points_registered ();
52 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME
,
57 struct _GNetworkMonitorNetlinkPrivate
60 GSource
*source
, *dump_source
;
62 GPtrArray
*dump_networks
;
65 static gboolean
read_netlink_messages (GSocket
*socket
,
66 GIOCondition condition
,
68 static gboolean
request_dump (GNetworkMonitorNetlink
*nl
,
72 g_network_monitor_netlink_init (GNetworkMonitorNetlink
*nl
)
74 nl
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (nl
,
75 G_TYPE_NETWORK_MONITOR_NETLINK
,
76 GNetworkMonitorNetlinkPrivate
);
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
= socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
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"),
116 if (setsockopt (sockfd
, SOL_SOCKET
, SO_PASSCRED
, &val
, sizeof (val
)) != 0)
119 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
120 _("Could not create network monitor: %s"),
126 nl
->priv
->sock
= g_socket_new_from_fd (sockfd
, error
);
129 g_prefix_error (error
, "%s", _("Could not create network monitor: "));
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
,
225 GInetAddress
*dest_addr
;
226 GInetAddressMask
*network
;
229 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
231 dest_addr
= g_inet_address_new_any (family
);
232 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
233 g_object_unref (dest_addr
);
234 g_return_if_fail (network
!= NULL
);
236 if (nl
->priv
->dump_networks
)
237 g_ptr_array_add (nl
->priv
->dump_networks
, network
);
240 g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl
), network
);
241 g_object_unref (network
);
246 remove_network (GNetworkMonitorNetlink
*nl
,
247 GSocketFamily family
,
252 GInetAddress
*dest_addr
;
253 GInetAddressMask
*network
;
256 dest_addr
= g_inet_address_new_from_bytes (dest
, family
);
258 dest_addr
= g_inet_address_new_any (family
);
259 network
= g_inet_address_mask_new (dest_addr
, dest_len
, NULL
);
260 g_object_unref (dest_addr
);
261 g_return_if_fail (network
!= NULL
);
263 if (nl
->priv
->dump_networks
)
265 GInetAddressMask
**dump_networks
= (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
;
268 for (i
= 0; i
< nl
->priv
->dump_networks
->len
; i
++)
270 if (g_inet_address_mask_equal (network
, dump_networks
[i
]))
271 g_ptr_array_remove_index_fast (nl
->priv
->dump_networks
, i
--);
273 g_object_unref (network
);
277 g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl
), network
);
278 g_object_unref (network
);
283 finish_dump (GNetworkMonitorNetlink
*nl
)
285 g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl
),
286 (GInetAddressMask
**)nl
->priv
->dump_networks
->pdata
,
287 nl
->priv
->dump_networks
->len
);
288 g_ptr_array_free (nl
->priv
->dump_networks
, FALSE
);
289 nl
->priv
->dump_networks
= NULL
;
293 read_netlink_messages (GSocket
*socket
,
294 GIOCondition condition
,
297 GNetworkMonitorNetlink
*nl
= user_data
;
300 GSocketControlMessage
**cmsgs
= NULL
;
301 gint num_cmsgs
= 0, i
, flags
;
302 GError
*error
= NULL
;
305 struct nlmsghdr
*msg
;
309 guint8
*dest
, *gateway
;
310 gboolean retval
= TRUE
;
315 flags
= MSG_PEEK
| MSG_TRUNC
;
316 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
317 NULL
, NULL
, &flags
, NULL
, &error
);
320 g_warning ("Error on netlink socket: %s", error
->message
);
321 g_error_free (error
);
322 if (nl
->priv
->dump_networks
)
327 iv
.buffer
= g_malloc (len
);
329 len
= g_socket_receive_message (nl
->priv
->sock
, NULL
, &iv
, 1,
330 &cmsgs
, &num_cmsgs
, NULL
, NULL
, &error
);
333 g_warning ("Error on netlink socket: %s", error
->message
);
334 g_error_free (error
);
335 if (nl
->priv
->dump_networks
)
340 if (num_cmsgs
!= 1 || !G_IS_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]))
343 creds
= g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (cmsgs
[0]));
344 sender
= g_credentials_get_unix_user (creds
, NULL
);
348 msg
= (struct nlmsghdr
*) iv
.buffer
;
349 for (; len
> 0; msg
= NLMSG_NEXT (msg
, len
))
351 if (!NLMSG_OK (msg
, (size_t) len
))
353 g_warning ("netlink message was truncated; shouldn't happen...");
358 switch (msg
->nlmsg_type
)
362 rtmsg
= NLMSG_DATA (msg
);
364 if (rtmsg
->rtm_family
!= AF_INET
&& rtmsg
->rtm_family
!= AF_INET6
)
366 if (rtmsg
->rtm_type
== RTN_UNREACHABLE
)
369 attrlen
= NLMSG_PAYLOAD (msg
, sizeof (struct rtmsg
));
370 attr
= RTM_RTA (rtmsg
);
371 dest
= gateway
= NULL
;
372 while (RTA_OK (attr
, attrlen
))
374 if (attr
->rta_type
== RTA_DST
)
375 dest
= RTA_DATA (attr
);
376 else if (attr
->rta_type
== RTA_GATEWAY
)
377 gateway
= RTA_DATA (attr
);
378 attr
= RTA_NEXT (attr
, attrlen
);
383 if (msg
->nlmsg_type
== RTM_NEWROUTE
)
384 add_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
, gateway
);
386 remove_network (nl
, rtmsg
->rtm_family
, rtmsg
->rtm_dst_len
, dest
, gateway
);
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 g_type_class_add_private (nl_class
, sizeof (GNetworkMonitorNetlinkPrivate
));
456 gobject_class
->finalize
= g_network_monitor_netlink_finalize
;
460 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface
*monitor_iface
)
465 g_network_monitor_netlink_initable_iface_init (GInitableIface
*iface
)
467 iface
->init
= g_network_monitor_netlink_initable_init
;