gio: Use the new private instance data declaration
[platform/upstream/glib.git] / gio / gnetworkmonitornetlink.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright 2011 Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #include "config.h"
22
23 #include <errno.h>
24 #include <unistd.h>
25
26 #include "gnetworkmonitornetlink.h"
27 #include "gcredentials.h"
28 #include "ginetaddressmask.h"
29 #include "ginitable.h"
30 #include "giomodule-priv.h"
31 #include "glibintl.h"
32 #include "glib/gstdio.h"
33 #include "gnetworkingprivate.h"
34 #include "gnetworkmonitor.h"
35 #include "gsocket.h"
36 #include "gunixcredentialsmessage.h"
37
38 /* must come at the end to pick system includes from
39  * gnetworkingprivate.h */
40 #include <linux/netlink.h>
41 #include <linux/rtnetlink.h>
42
43 static void g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *iface);
44 static void g_network_monitor_netlink_initable_iface_init (GInitableIface *iface);
45
46 struct _GNetworkMonitorNetlinkPrivate
47 {
48   GSocket *sock;
49   GSource *source, *dump_source;
50
51   GPtrArray *dump_networks;
52 };
53
54 static gboolean read_netlink_messages (GSocket             *socket,
55                                        GIOCondition         condition,
56                                        gpointer             user_data);
57 static gboolean request_dump (GNetworkMonitorNetlink  *nl,
58                               GError                 **error);
59
60 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
61 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE,
62                          G_ADD_PRIVATE (GNetworkMonitorNetlink)
63                          G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
64                                                 g_network_monitor_netlink_iface_init)
65                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
66                                                 g_network_monitor_netlink_initable_iface_init)
67                          _g_io_modules_ensure_extension_points_registered ();
68                          g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
69                                                          g_define_type_id,
70                                                          "netlink",
71                                                          20))
72
73 static void
74 g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
75 {
76   nl->priv = g_network_monitor_netlink_get_private (nl);
77 }
78
79
80 static gboolean
81 g_network_monitor_netlink_initable_init (GInitable     *initable,
82                                          GCancellable  *cancellable,
83                                          GError       **error)
84 {
85   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
86   gint sockfd;
87   struct sockaddr_nl snl;
88
89   /* We create the socket the old-school way because sockaddr_netlink
90    * can't be represented as a GSocketAddress
91    */
92   sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
93   if (sockfd == -1)
94     {
95       int errsv = errno;
96       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
97                    _("Could not create network monitor: %s"),
98                    g_strerror (errno));
99       return FALSE;
100     }
101
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)
106     {
107       int errsv = errno;
108       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
109                    _("Could not create network monitor: %s"),
110                    g_strerror (errno));
111       (void) g_close (sockfd, NULL);
112       return FALSE;
113     }
114
115   nl->priv->sock = g_socket_new_from_fd (sockfd, error);
116   if (error)
117     {
118       g_prefix_error (error, "%s", _("Could not create network monitor: "));
119       (void) g_close (sockfd, NULL);
120       return FALSE;
121     }
122
123   if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
124                             TRUE, NULL))
125     {
126       int errsv = errno;
127       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
128                    _("Could not create network monitor: %s"),
129                    g_strerror (errno));
130       return FALSE;
131     }
132
133   /* Request the current state */
134   if (!request_dump (nl, error))
135     return FALSE;
136
137   /* And read responses; since we haven't yet marked the socket
138    * non-blocking, each call will block until a message is received.
139    */
140   while (nl->priv->dump_networks)
141     {
142       if (!read_netlink_messages (NULL, G_IO_IN, nl))
143         break;
144     }
145
146   g_socket_set_blocking (nl->priv->sock, FALSE);
147   nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL);
148   g_source_set_callback (nl->priv->source,
149                          (GSourceFunc) read_netlink_messages, nl, NULL);
150   g_source_attach (nl->priv->source,
151                    g_main_context_get_thread_default ());
152
153   return TRUE;
154 }
155
156 static gboolean
157 request_dump (GNetworkMonitorNetlink  *nl,
158               GError                 **error)
159 {
160   struct nlmsghdr *n;
161   struct rtgenmsg *gen;
162   gchar buf[NLMSG_SPACE (sizeof (*gen))];
163
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;
169   n->nlmsg_pid = 0;
170   gen = NLMSG_DATA (n);
171   gen->rtgen_family = AF_UNSPEC;
172
173   if (g_socket_send (nl->priv->sock, buf, sizeof (buf),
174                      NULL, error) < 0)
175     {
176       g_prefix_error (error, "%s", _("Could not get network status: "));
177       return FALSE;
178     }
179
180   nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref);
181   return TRUE;
182 }
183
184 static gboolean
185 timeout_request_dump (gpointer user_data)
186 {
187   GNetworkMonitorNetlink *nl = user_data;
188
189   g_source_destroy (nl->priv->dump_source);
190   g_source_unref (nl->priv->dump_source);
191   nl->priv->dump_source = NULL;
192
193   request_dump (nl, NULL);
194
195   return FALSE;
196 }
197
198 static void
199 queue_request_dump (GNetworkMonitorNetlink *nl)
200 {
201   if (nl->priv->dump_networks)
202     return;
203
204   if (nl->priv->dump_source)
205     {
206       g_source_destroy (nl->priv->dump_source);
207       g_source_unref (nl->priv->dump_source);
208     }
209
210   nl->priv->dump_source = g_timeout_source_new (1000);
211   g_source_set_callback (nl->priv->dump_source,
212                          (GSourceFunc) timeout_request_dump, nl, NULL);
213   g_source_attach (nl->priv->dump_source,
214                    g_main_context_get_thread_default ());
215 }
216
217 static void
218 add_network (GNetworkMonitorNetlink *nl,
219              GSocketFamily           family,
220              gint                    dest_len,
221              guint8                 *dest,
222              guint8                 *gateway)
223 {
224   GInetAddress *dest_addr;
225   GInetAddressMask *network;
226
227   if (dest)
228     dest_addr = g_inet_address_new_from_bytes (dest, family);
229   else
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);
234
235   if (nl->priv->dump_networks)
236     g_ptr_array_add (nl->priv->dump_networks, network);
237   else
238     {
239       g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
240       g_object_unref (network);
241     }
242 }
243
244 static void
245 remove_network (GNetworkMonitorNetlink *nl,
246                 GSocketFamily           family,
247                 gint                    dest_len,
248                 guint8                 *dest,
249                 guint8                 *gateway)
250 {
251   GInetAddress *dest_addr;
252   GInetAddressMask *network;
253
254   if (dest)
255     dest_addr = g_inet_address_new_from_bytes (dest, family);
256   else
257     dest_addr = g_inet_address_new_any (family);
258   network = g_inet_address_mask_new (dest_addr, dest_len, NULL);
259   g_object_unref (dest_addr);
260   g_return_if_fail (network != NULL);
261
262   if (nl->priv->dump_networks)
263     {
264       GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata;
265       int i;
266
267       for (i = 0; i < nl->priv->dump_networks->len; i++)
268         {
269           if (g_inet_address_mask_equal (network, dump_networks[i]))
270             g_ptr_array_remove_index_fast (nl->priv->dump_networks, i--);
271         }
272       g_object_unref (network);
273     }
274   else
275     {
276       g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network);
277       g_object_unref (network);
278     }
279 }
280
281 static void
282 finish_dump (GNetworkMonitorNetlink *nl)
283 {
284   g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl),
285                                        (GInetAddressMask **)nl->priv->dump_networks->pdata,
286                                        nl->priv->dump_networks->len);
287   g_ptr_array_free (nl->priv->dump_networks, TRUE);
288   nl->priv->dump_networks = NULL;
289 }
290
291 static gboolean
292 read_netlink_messages (GSocket      *socket,
293                        GIOCondition  condition,
294                        gpointer      user_data)
295 {
296   GNetworkMonitorNetlink *nl = user_data;
297   GInputVector iv;
298   gssize len;
299   GSocketControlMessage **cmsgs = NULL;
300   gint num_cmsgs = 0, i, flags;
301   GError *error = NULL;
302   GCredentials *creds;
303   uid_t sender;
304   struct nlmsghdr *msg;
305   struct rtmsg *rtmsg;
306   struct rtattr *attr;
307   gsize attrlen;
308   guint8 *dest, *gateway;
309   gboolean retval = TRUE;
310
311   iv.buffer = NULL;
312   iv.size = 0;
313
314   flags = MSG_PEEK | MSG_TRUNC;
315   len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
316                                   NULL, NULL, &flags, NULL, &error);
317   if (len < 0)
318     {
319       g_warning ("Error on netlink socket: %s", error->message);
320       g_error_free (error);
321       if (nl->priv->dump_networks)
322         finish_dump (nl);
323       return FALSE;
324     }
325
326   iv.buffer = g_malloc (len);
327   iv.size = len;
328   len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
329                                   &cmsgs, &num_cmsgs, NULL, NULL, &error);
330   if (len < 0)
331     {
332       g_warning ("Error on netlink socket: %s", error->message);
333       g_error_free (error);
334       if (nl->priv->dump_networks)
335         finish_dump (nl);
336       return FALSE;
337     }
338
339   if (num_cmsgs != 1 || !G_IS_UNIX_CREDENTIALS_MESSAGE (cmsgs[0]))
340     goto done;
341
342   creds = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (cmsgs[0]));
343   sender = g_credentials_get_unix_user (creds, NULL);
344   if (sender != 0)
345     goto done;
346
347   msg = (struct nlmsghdr *) iv.buffer;
348   for (; len > 0; msg = NLMSG_NEXT (msg, len))
349     {
350       if (!NLMSG_OK (msg, (size_t) len))
351         {
352           g_warning ("netlink message was truncated; shouldn't happen...");
353           retval = FALSE;
354           goto done;
355         }
356
357       switch (msg->nlmsg_type)
358         {
359         case RTM_NEWROUTE:
360         case RTM_DELROUTE:
361           rtmsg = NLMSG_DATA (msg);
362
363           if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
364             continue;
365           if (rtmsg->rtm_type == RTN_UNREACHABLE)
366             continue;
367
368           attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
369           attr = RTM_RTA (rtmsg);
370           dest = gateway = NULL;
371           while (RTA_OK (attr, attrlen))
372             {
373               if (attr->rta_type == RTA_DST)
374                 dest = RTA_DATA (attr);
375               else if (attr->rta_type == RTA_GATEWAY)
376                 gateway = RTA_DATA (attr);
377               attr = RTA_NEXT (attr, attrlen);
378             }
379
380           if (dest || gateway)
381             {
382               if (msg->nlmsg_type == RTM_NEWROUTE)
383                 add_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest, gateway);
384               else
385                 remove_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest, gateway);
386               queue_request_dump (nl);
387             }
388           break;
389
390         case NLMSG_DONE:
391           finish_dump (nl);
392           goto done;
393
394         case NLMSG_ERROR:
395           {
396             struct nlmsgerr *e = NLMSG_DATA (msg);
397
398             g_warning ("netlink error: %s", g_strerror (-e->error));
399           }
400           retval = FALSE;
401           goto done;
402
403         default:
404           g_warning ("unexpected netlink message %d", msg->nlmsg_type);
405           retval = FALSE;
406           goto done;
407         }
408     }
409
410  done:
411   for (i = 0; i < num_cmsgs; i++)
412     g_object_unref (cmsgs[i]);
413   g_free (cmsgs);
414
415   g_free (iv.buffer);
416
417   if (!retval && nl->priv->dump_networks)
418     finish_dump (nl);
419   return retval;
420 }
421
422 static void
423 g_network_monitor_netlink_finalize (GObject *object)
424 {
425   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
426
427   if (nl->priv->sock)
428     {
429       g_socket_close (nl->priv->sock, NULL);
430       g_object_unref (nl->priv->sock);
431     }
432
433   if (nl->priv->source)
434     {
435       g_source_destroy (nl->priv->source);
436       g_source_unref (nl->priv->source);
437     }
438
439   if (nl->priv->dump_source)
440     {
441       g_source_destroy (nl->priv->dump_source);
442       g_source_unref (nl->priv->dump_source);
443     }
444
445   G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
446 }
447
448 static void
449 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
450 {
451   GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
452
453   gobject_class->finalize  = g_network_monitor_netlink_finalize;
454 }
455
456 static void
457 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
458 {
459 }
460
461 static void
462 g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
463 {
464   iface->init = g_network_monitor_netlink_initable_init;
465 }