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