nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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 gint flags;
297 GError *error = NULL;
298 GSocketAddress *addr;
299 struct nlmsghdr *msg;
300 struct rtmsg *rtmsg;
301 struct rtattr *attr;
302 struct sockaddr_nl source_sockaddr;
303 gsize attrlen;
304 guint8 *dest, *gateway, *oif;
305 gboolean retval = TRUE;
306  
307 iv.buffer = NULL;
308 iv.size = 0;
309  
310 flags = MSG_PEEK | MSG_TRUNC;
311 len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1,
312 NULL, NULL, &flags, NULL, &error);
313 if (len < 0)
314 {
315 g_warning ("Error on netlink socket: %s", error->message);
316 g_error_free (error);
317 if (nl->priv->dump_networks)
318 finish_dump (nl);
319 return FALSE;
320 }
321  
322 iv.buffer = g_malloc (len);
323 iv.size = len;
324 len = g_socket_receive_message (nl->priv->sock, &addr, &iv, 1,
325 NULL, NULL, NULL, NULL, &error);
326 if (len < 0)
327 {
328 g_warning ("Error on netlink socket: %s", error->message);
329 g_error_free (error);
330 if (nl->priv->dump_networks)
331 finish_dump (nl);
332 return FALSE;
333 }
334  
335 if (!g_socket_address_to_native (addr, &source_sockaddr, sizeof (source_sockaddr), &error))
336 {
337 g_warning ("Error on netlink socket: %s", error->message);
338 g_error_free (error);
339 if (nl->priv->dump_networks)
340 finish_dump (nl);
341 return FALSE;
342 }
343  
344 /* If the sender port id is 0 (not fakeable) then the message is from the kernel */
345 if (source_sockaddr.nl_pid != 0)
346 goto done;
347  
348 msg = (struct nlmsghdr *) iv.buffer;
349 for (; len > 0; msg = NLMSG_NEXT (msg, len))
350 {
351 if (!NLMSG_OK (msg, (size_t) len))
352 {
353 g_warning ("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 UNALIGNED_IN6_IS_ADDR_MC_LINKLOCAL (dest))
396 continue;
397  
398 if (msg->nlmsg_type == RTM_NEWROUTE)
399 add_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest);
400 else
401 remove_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest);
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_warning ("netlink error: %s", g_strerror (-e->error));
415 }
416 retval = FALSE;
417 goto done;
418  
419 default:
420 g_warning ("unexpected netlink message %d", msg->nlmsg_type);
421 retval = FALSE;
422 goto done;
423 }
424 }
425  
426 done:
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 }