• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.1 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 GInitableIface *initable_parent_iface;
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   GMainContext *context;
51 
52   GPtrArray *dump_networks;
53 };
54 
55 static gboolean read_netlink_messages (GNetworkMonitorNetlink  *nl,
56                                        GError                 **error);
57 static gboolean read_netlink_messages_callback (GSocket             *socket,
58                                                 GIOCondition         condition,
59                                                 gpointer             user_data);
60 static gboolean request_dump (GNetworkMonitorNetlink  *nl,
61                               GError                 **error);
62 
63 #define g_network_monitor_netlink_get_type _g_network_monitor_netlink_get_type
64 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNetlink, g_network_monitor_netlink, G_TYPE_NETWORK_MONITOR_BASE,
65                          G_ADD_PRIVATE (GNetworkMonitorNetlink)
66                          G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
67                                                 g_network_monitor_netlink_iface_init)
68                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
69                                                 g_network_monitor_netlink_initable_iface_init)
70                          _g_io_modules_ensure_extension_points_registered ();
71                          g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
72                                                          g_define_type_id,
73                                                          "netlink",
74                                                          20))
75 
76 static void
g_network_monitor_netlink_init(GNetworkMonitorNetlink * nl)77 g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl)
78 {
79   nl->priv = g_network_monitor_netlink_get_instance_private (nl);
80 }
81 
82 static gboolean
g_network_monitor_netlink_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)83 g_network_monitor_netlink_initable_init (GInitable     *initable,
84                                          GCancellable  *cancellable,
85                                          GError       **error)
86 {
87   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
88   gint sockfd;
89   struct sockaddr_nl snl;
90 
91   /* We create the socket the old-school way because sockaddr_netlink
92    * can't be represented as a GSocketAddress
93    */
94   sockfd = g_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, NULL);
95   if (sockfd == -1)
96     {
97       int errsv = errno;
98       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
99                    _("Could not create network monitor: %s"),
100                    g_strerror (errsv));
101       return FALSE;
102     }
103 
104   snl.nl_family = AF_NETLINK;
105   snl.nl_pid = snl.nl_pad = 0;
106   snl.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
107   if (bind (sockfd, (struct sockaddr *)&snl, sizeof (snl)) != 0)
108     {
109       int errsv = errno;
110       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
111                    _("Could not create network monitor: %s"),
112                    g_strerror (errsv));
113       (void) g_close (sockfd, NULL);
114       return FALSE;
115     }
116 
117   nl->priv->sock = g_socket_new_from_fd (sockfd, error);
118   if (!nl->priv->sock)
119     {
120       g_prefix_error (error, "%s", _("Could not create network monitor: "));
121       (void) g_close (sockfd, NULL);
122       return FALSE;
123     }
124 
125   if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
126 			    TRUE, NULL))
127     {
128       int errsv = errno;
129       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
130                    _("Could not create network monitor: %s"),
131                    g_strerror (errsv));
132       return FALSE;
133     }
134 
135   /* Request the current state */
136   if (!request_dump (nl, error))
137     return FALSE;
138 
139   /* And read responses; since we haven't yet marked the socket
140    * non-blocking, each call will block until a message is received.
141    */
142   while (nl->priv->dump_networks)
143     {
144       GError *local_error = NULL;
145       if (!read_netlink_messages (nl, &local_error))
146         {
147           g_warning ("%s", local_error->message);
148           g_clear_error (&local_error);
149           break;
150         }
151     }
152 
153   g_socket_set_blocking (nl->priv->sock, FALSE);
154   nl->priv->context = g_main_context_ref_thread_default ();
155   nl->priv->source = g_socket_create_source (nl->priv->sock, G_IO_IN, NULL);
156   g_source_set_callback (nl->priv->source,
157                          (GSourceFunc) read_netlink_messages_callback, nl, NULL);
158   g_source_attach (nl->priv->source, nl->priv->context);
159 
160   return initable_parent_iface->init (initable, cancellable, error);
161 }
162 
163 static gboolean
request_dump(GNetworkMonitorNetlink * nl,GError ** error)164 request_dump (GNetworkMonitorNetlink  *nl,
165               GError                 **error)
166 {
167   struct nlmsghdr *n;
168   struct rtgenmsg *gen;
169   gchar buf[NLMSG_SPACE (sizeof (*gen))];
170 
171   memset (buf, 0, sizeof (buf));
172   n = (struct nlmsghdr*) buf;
173   n->nlmsg_len = NLMSG_LENGTH (sizeof (*gen));
174   n->nlmsg_type = RTM_GETROUTE;
175   n->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
176   n->nlmsg_pid = 0;
177   gen = NLMSG_DATA (n);
178   gen->rtgen_family = AF_UNSPEC;
179 
180   if (g_socket_send (nl->priv->sock, buf, sizeof (buf),
181                      NULL, error) < 0)
182     {
183       g_prefix_error (error, "%s", _("Could not get network status: "));
184       return FALSE;
185     }
186 
187   nl->priv->dump_networks = g_ptr_array_new_with_free_func (g_object_unref);
188   return TRUE;
189 }
190 
191 static gboolean
timeout_request_dump(gpointer user_data)192 timeout_request_dump (gpointer user_data)
193 {
194   GNetworkMonitorNetlink *nl = user_data;
195 
196   g_source_destroy (nl->priv->dump_source);
197   g_source_unref (nl->priv->dump_source);
198   nl->priv->dump_source = NULL;
199 
200   request_dump (nl, NULL);
201 
202   return FALSE;
203 }
204 
205 static void
queue_request_dump(GNetworkMonitorNetlink * nl)206 queue_request_dump (GNetworkMonitorNetlink *nl)
207 {
208   if (nl->priv->dump_networks)
209     return;
210 
211   if (nl->priv->dump_source)
212     {
213       g_source_destroy (nl->priv->dump_source);
214       g_source_unref (nl->priv->dump_source);
215     }
216 
217   nl->priv->dump_source = g_timeout_source_new_seconds (1);
218   g_source_set_callback (nl->priv->dump_source,
219                          (GSourceFunc) timeout_request_dump, nl, NULL);
220   g_source_attach (nl->priv->dump_source, nl->priv->context);
221 }
222 
223 static GInetAddressMask *
create_inet_address_mask(GSocketFamily family,const guint8 * dest,gsize dest_len)224 create_inet_address_mask (GSocketFamily  family,
225                           const guint8  *dest,
226                           gsize          dest_len)
227 {
228   GInetAddress *dest_addr;
229   GInetAddressMask *network;
230 
231   if (dest)
232     dest_addr = g_inet_address_new_from_bytes (dest, family);
233   else
234     dest_addr = g_inet_address_new_any (family);
235   network = g_inet_address_mask_new (dest_addr, dest_len, NULL);
236   g_object_unref (dest_addr);
237 
238   return network;
239 }
240 
241 static void
add_network(GNetworkMonitorNetlink * nl,GSocketFamily family,const guint8 * dest,gsize dest_len)242 add_network (GNetworkMonitorNetlink *nl,
243              GSocketFamily           family,
244              const guint8           *dest,
245              gsize                   dest_len)
246 {
247   GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
248   g_return_if_fail (network != NULL);
249 
250   if (nl->priv->dump_networks)
251     g_ptr_array_add (nl->priv->dump_networks, g_object_ref (network));
252   else
253     g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (nl), network);
254 
255   g_object_unref (network);
256 }
257 
258 static void
remove_network(GNetworkMonitorNetlink * nl,GSocketFamily family,const guint8 * dest,gsize dest_len)259 remove_network (GNetworkMonitorNetlink *nl,
260                 GSocketFamily           family,
261                 const guint8           *dest,
262                 gsize                   dest_len)
263 {
264   GInetAddressMask *network = create_inet_address_mask (family, dest, dest_len);
265   g_return_if_fail (network != NULL);
266 
267   if (nl->priv->dump_networks)
268     {
269       GInetAddressMask **dump_networks = (GInetAddressMask **)nl->priv->dump_networks->pdata;
270       guint i;
271 
272       for (i = 0; i < nl->priv->dump_networks->len; i++)
273         {
274           if (g_inet_address_mask_equal (network, dump_networks[i]))
275             g_ptr_array_remove_index_fast (nl->priv->dump_networks, i--);
276         }
277     }
278   else
279     {
280       g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (nl), network);
281     }
282 
283   g_object_unref (network);
284 }
285 
286 static void
finish_dump(GNetworkMonitorNetlink * nl)287 finish_dump (GNetworkMonitorNetlink *nl)
288 {
289   g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl),
290                                        (GInetAddressMask **)nl->priv->dump_networks->pdata,
291                                        nl->priv->dump_networks->len);
292   g_ptr_array_free (nl->priv->dump_networks, TRUE);
293   nl->priv->dump_networks = NULL;
294 }
295 
296 static gboolean
read_netlink_messages(GNetworkMonitorNetlink * nl,GError ** error)297 read_netlink_messages (GNetworkMonitorNetlink  *nl,
298                        GError                 **error)
299 {
300   GInputVector iv;
301   gssize len;
302   gint flags;
303   GError *local_error = NULL;
304   GSocketAddress *addr = NULL;
305   struct nlmsghdr *msg;
306   struct rtmsg *rtmsg;
307   struct rtattr *attr;
308   struct sockaddr_nl source_sockaddr;
309   gsize attrlen;
310   guint8 *dest, *gateway, *oif;
311   gboolean retval = TRUE;
312 
313   iv.buffer = NULL;
314   iv.size = 0;
315 
316   flags = MSG_PEEK | MSG_TRUNC;
317   len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
318                                   NULL, NULL, &flags, NULL, &local_error);
319   if (len < 0)
320     {
321       retval = FALSE;
322       goto done;
323     }
324 
325   iv.buffer = g_malloc (len);
326   iv.size = len;
327   len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1,
328                                   NULL, NULL, NULL, NULL, &local_error);
329   if (len < 0)
330     {
331       retval = FALSE;
332       goto done;
333     }
334 
335   if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &local_error))
336     {
337       retval = FALSE;
338       goto done;
339     }
340 
341   /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
342   if (source_sockaddr.nl_pid != 0)
343     goto done;
344 
345   msg = (struct nlmsghdr *) iv.buffer;
346   for (; len > 0; msg = NLMSG_NEXT (msg, len))
347     {
348       if (!NLMSG_OK (msg, (size_t) len))
349         {
350           g_set_error_literal (&local_error,
351                                G_IO_ERROR,
352                                G_IO_ERROR_PARTIAL_INPUT,
353                                "netlink message was truncated; shouldn't happen...");
354           retval = FALSE;
355           goto done;
356         }
357 
358       switch (msg->nlmsg_type)
359         {
360         case RTM_NEWROUTE:
361         case RTM_DELROUTE:
362           rtmsg = NLMSG_DATA (msg);
363 
364           if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6)
365             continue;
366           if (rtmsg->rtm_type == RTN_UNREACHABLE)
367             continue;
368 
369           attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg));
370           attr = RTM_RTA (rtmsg);
371           dest = gateway = oif = NULL;
372           while (RTA_OK (attr, attrlen))
373             {
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               else if (attr->rta_type == RTA_OIF)
379                 oif = RTA_DATA (attr);
380               attr = RTA_NEXT (attr, attrlen);
381             }
382 
383           if (dest || gateway || oif)
384             {
385               /* Unless we're processing the results of a dump, ignore
386                * IPv6 link-local multicast routes, which are added and
387                * removed all the time for some reason.
388                */
389 #define UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL(a)           \
390               ((a[0] == 0xff) && ((a[1] & 0xf) == 0x2))
391 
392               if (!nl->priv->dump_networks &&
393                   rtmsg->rtm_family == AF_INET6 &&
394                   rtmsg->rtm_dst_len != 0 &&
395                   (dest && UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest)))
396                 continue;
397 
398               if (msg->nlmsg_type == RTM_NEWROUTE)
399                 add_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
400               else
401                 remove_network (nl, rtmsg->rtm_family, dest, rtmsg->rtm_dst_len);
402               queue_request_dump (nl);
403             }
404           break;
405 
406         case NLMSG_DONE:
407           finish_dump (nl);
408           goto done;
409 
410         case NLMSG_ERROR:
411           {
412             struct nlmsgerr *e = NLMSG_DATA (msg);
413 
414             g_set_error (&local_error,
415                          G_IO_ERROR,
416                          g_io_error_from_errno (-e->error),
417                          "netlink error: %s",
418                          g_strerror (-e->error));
419           }
420           retval = FALSE;
421           goto done;
422 
423         default:
424           g_set_error (&local_error,
425                        G_IO_ERROR,
426                        G_IO_ERROR_INVALID_DATA,
427                        "unexpected netlink message %d",
428                        msg->nlmsg_type);
429           retval = FALSE;
430           goto done;
431         }
432     }
433 
434  done:
435   g_free (iv.buffer);
436   g_clear_object (&addr);
437 
438   if (!retval && nl->priv->dump_networks)
439     finish_dump (nl);
440 
441   if (local_error)
442     g_propagate_prefixed_error (error, local_error, "Error on netlink socket: ");
443 
444   return retval;
445 }
446 
447 static void
g_network_monitor_netlink_finalize(GObject * object)448 g_network_monitor_netlink_finalize (GObject *object)
449 {
450   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object);
451 
452   if (nl->priv->source)
453     {
454       g_source_destroy (nl->priv->source);
455       g_source_unref (nl->priv->source);
456     }
457 
458   if (nl->priv->dump_source)
459     {
460       g_source_destroy (nl->priv->dump_source);
461       g_source_unref (nl->priv->dump_source);
462     }
463 
464   if (nl->priv->sock)
465     {
466       g_socket_close (nl->priv->sock, NULL);
467       g_object_unref (nl->priv->sock);
468     }
469 
470   g_clear_pointer (&nl->priv->context, g_main_context_unref);
471   g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref);
472 
473   G_OBJECT_CLASS (g_network_monitor_netlink_parent_class)->finalize (object);
474 }
475 
476 static gboolean
read_netlink_messages_callback(GSocket * socket,GIOCondition condition,gpointer user_data)477 read_netlink_messages_callback (GSocket      *socket,
478                                 GIOCondition  condition,
479                                 gpointer      user_data)
480 {
481   GError *error = NULL;
482   GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (user_data);
483 
484   if (!read_netlink_messages (nl, &error))
485     {
486       g_warning ("Error reading netlink message: %s", error->message);
487       g_clear_error (&error);
488       return FALSE;
489     }
490 
491   return TRUE;
492 }
493 
494 static void
g_network_monitor_netlink_class_init(GNetworkMonitorNetlinkClass * nl_class)495 g_network_monitor_netlink_class_init (GNetworkMonitorNetlinkClass *nl_class)
496 {
497   GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
498 
499   gobject_class->finalize = g_network_monitor_netlink_finalize;
500 }
501 
502 static void
g_network_monitor_netlink_iface_init(GNetworkMonitorInterface * monitor_iface)503 g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface)
504 {
505 }
506 
507 static void
g_network_monitor_netlink_initable_iface_init(GInitableIface * iface)508 g_network_monitor_netlink_initable_iface_init (GInitableIface *iface)
509 {
510   initable_parent_iface = g_type_interface_peek_parent (iface);
511 
512   iface->init = g_network_monitor_netlink_initable_init;
513 }
514