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