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 |
77 | g_network_monitor_netlink_init (GNetworkMonitorNetlink *nl) |
78 | { |
79 | nl->priv = g_network_monitor_netlink_get_instance_private (self: nl); |
80 | } |
81 | |
82 | static gboolean |
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 (err: error, G_IO_ERROR, code: g_io_error_from_errno (err_no: errsv), |
99 | _("Could not create network monitor: %s" ), |
100 | g_strerror (errnum: 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 (fd: sockfd, addr: (struct sockaddr *)&snl, len: sizeof (snl)) != 0) |
108 | { |
109 | int errsv = errno; |
110 | g_set_error (err: error, G_IO_ERROR, code: g_io_error_from_errno (err_no: errsv), |
111 | _("Could not create network monitor: %s" ), |
112 | g_strerror (errnum: errsv)); |
113 | (void) g_close (fd: sockfd, NULL); |
114 | return FALSE; |
115 | } |
116 | |
117 | nl->priv->sock = g_socket_new_from_fd (fd: sockfd, error); |
118 | if (!nl->priv->sock) |
119 | { |
120 | g_prefix_error (err: error, format: "%s" , _("Could not create network monitor: " )); |
121 | (void) g_close (fd: sockfd, NULL); |
122 | return FALSE; |
123 | } |
124 | |
125 | if (!g_socket_set_option (socket: nl->priv->sock, SOL_SOCKET, SO_PASSCRED, |
126 | TRUE, NULL)) |
127 | { |
128 | int errsv = errno; |
129 | g_set_error (err: error, G_IO_ERROR, code: g_io_error_from_errno (err_no: errsv), |
130 | _("Could not create network monitor: %s" ), |
131 | g_strerror (errnum: 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, error: &local_error)) |
146 | { |
147 | g_warning ("%s" , local_error->message); |
148 | g_clear_error (err: &local_error); |
149 | break; |
150 | } |
151 | } |
152 | |
153 | g_socket_set_blocking (socket: nl->priv->sock, FALSE); |
154 | nl->priv->context = g_main_context_ref_thread_default (); |
155 | nl->priv->source = g_socket_create_source (socket: nl->priv->sock, condition: G_IO_IN, NULL); |
156 | g_source_set_callback (source: nl->priv->source, |
157 | func: (GSourceFunc) read_netlink_messages_callback, data: nl, NULL); |
158 | g_source_attach (source: nl->priv->source, context: nl->priv->context); |
159 | |
160 | return initable_parent_iface->init (initable, cancellable, error); |
161 | } |
162 | |
163 | static gboolean |
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 (s: buf, c: 0, n: 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 (socket: nl->priv->sock, buffer: buf, size: sizeof (buf), |
181 | NULL, error) < 0) |
182 | { |
183 | g_prefix_error (err: error, format: "%s" , _("Could not get network status: " )); |
184 | return FALSE; |
185 | } |
186 | |
187 | nl->priv->dump_networks = g_ptr_array_new_with_free_func (element_free_func: g_object_unref); |
188 | return TRUE; |
189 | } |
190 | |
191 | static gboolean |
192 | timeout_request_dump (gpointer user_data) |
193 | { |
194 | GNetworkMonitorNetlink *nl = user_data; |
195 | |
196 | g_source_destroy (source: nl->priv->dump_source); |
197 | g_source_unref (source: 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 |
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 (source: nl->priv->dump_source); |
214 | g_source_unref (source: nl->priv->dump_source); |
215 | } |
216 | |
217 | nl->priv->dump_source = g_timeout_source_new_seconds (interval: 1); |
218 | g_source_set_callback (source: nl->priv->dump_source, |
219 | func: (GSourceFunc) timeout_request_dump, data: nl, NULL); |
220 | g_source_attach (source: nl->priv->dump_source, context: nl->priv->context); |
221 | } |
222 | |
223 | static GInetAddressMask * |
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 (bytes: dest, family); |
233 | else |
234 | dest_addr = g_inet_address_new_any (family); |
235 | network = g_inet_address_mask_new (addr: dest_addr, length: dest_len, NULL); |
236 | g_object_unref (object: dest_addr); |
237 | |
238 | return network; |
239 | } |
240 | |
241 | static void |
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 (array: 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 (object: network); |
256 | } |
257 | |
258 | static void |
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 (mask: network, mask2: dump_networks[i])) |
275 | g_ptr_array_remove_index_fast (array: nl->priv->dump_networks, index_: 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 (object: network); |
284 | } |
285 | |
286 | static void |
287 | finish_dump (GNetworkMonitorNetlink *nl) |
288 | { |
289 | g_network_monitor_base_set_networks (G_NETWORK_MONITOR_BASE (nl), |
290 | networks: (GInetAddressMask **)nl->priv->dump_networks->pdata, |
291 | length: nl->priv->dump_networks->len); |
292 | g_ptr_array_free (array: nl->priv->dump_networks, TRUE); |
293 | nl->priv->dump_networks = NULL; |
294 | } |
295 | |
296 | static gboolean |
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 (socket: nl->priv->sock, NULL, vectors: &iv, num_vectors: 1, |
318 | NULL, NULL, flags: &flags, NULL, error: &local_error); |
319 | if (len < 0) |
320 | { |
321 | retval = FALSE; |
322 | goto done; |
323 | } |
324 | |
325 | iv.buffer = g_malloc (n_bytes: len); |
326 | iv.size = len; |
327 | len = g_socket_receive_message (socket: nl->priv->sock, address: &addr, vectors: &iv, num_vectors: 1, |
328 | NULL, NULL, NULL, NULL, error: &local_error); |
329 | if (len < 0) |
330 | { |
331 | retval = FALSE; |
332 | goto done; |
333 | } |
334 | |
335 | if (!g_socket_address_to_native (address: addr, dest: &source_sockaddr, destlen: sizeof (source_sockaddr), error: &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 (err: &local_error, |
351 | G_IO_ERROR, |
352 | code: G_IO_ERROR_PARTIAL_INPUT, |
353 | message: "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, family: rtmsg->rtm_family, dest, dest_len: rtmsg->rtm_dst_len); |
400 | else |
401 | remove_network (nl, family: rtmsg->rtm_family, dest, dest_len: 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 (err: &local_error, |
415 | G_IO_ERROR, |
416 | code: g_io_error_from_errno (err_no: -e->error), |
417 | format: "netlink error: %s" , |
418 | g_strerror (errnum: -e->error)); |
419 | } |
420 | retval = FALSE; |
421 | goto done; |
422 | |
423 | default: |
424 | g_set_error (err: &local_error, |
425 | G_IO_ERROR, |
426 | code: G_IO_ERROR_INVALID_DATA, |
427 | format: "unexpected netlink message %d" , |
428 | msg->nlmsg_type); |
429 | retval = FALSE; |
430 | goto done; |
431 | } |
432 | } |
433 | |
434 | done: |
435 | g_free (mem: 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 (dest: error, src: local_error, format: "Error on netlink socket: " ); |
443 | |
444 | return retval; |
445 | } |
446 | |
447 | static void |
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 (source: nl->priv->source); |
455 | g_source_unref (source: nl->priv->source); |
456 | } |
457 | |
458 | if (nl->priv->dump_source) |
459 | { |
460 | g_source_destroy (source: nl->priv->dump_source); |
461 | g_source_unref (source: nl->priv->dump_source); |
462 | } |
463 | |
464 | if (nl->priv->sock) |
465 | { |
466 | g_socket_close (socket: nl->priv->sock, NULL); |
467 | g_object_unref (object: 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 |
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: &error)) |
485 | { |
486 | g_warning ("Error reading netlink message: %s" , error->message); |
487 | g_clear_error (err: &error); |
488 | return FALSE; |
489 | } |
490 | |
491 | return TRUE; |
492 | } |
493 | |
494 | static void |
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 |
503 | g_network_monitor_netlink_iface_init (GNetworkMonitorInterface *monitor_iface) |
504 | { |
505 | } |
506 | |
507 | static void |
508 | g_network_monitor_netlink_initable_iface_init (GInitableIface *iface) |
509 | { |
510 | initable_parent_iface = g_type_interface_peek_parent (g_iface: iface); |
511 | |
512 | iface->init = g_network_monitor_netlink_initable_init; |
513 | } |
514 | |