1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* nm-ip6-manager.c - Handle IPv6 address configuration for NetworkManager
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Copyright (C) 2009 - 2010 Red Hat, Inc.
22 #include <netinet/icmp6.h>
24 #include <netlink/route/addr.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink/route/route.h>
28 #include "nm-ip6-manager.h"
29 #include "nm-netlink-monitor.h"
30 #include "nm-netlink-utils.h"
31 #include "nm-netlink-compat.h"
32 #include "NetworkManagerUtils.h"
33 #include "nm-marshal.h"
34 #include "nm-logging.h"
36 /* Pre-DHCP addrconf timeout, in seconds */
37 #define NM_IP6_TIMEOUT 20
39 /* FIXME? Stolen from the kernel sources */
40 #define IF_RA_OTHERCONF 0x80
41 #define IF_RA_MANAGED 0x40
42 #define IF_RA_RCVD 0x20
43 #define IF_RS_SENT 0x10
46 NMNetlinkMonitor *monitor;
50 struct nl_cache *addr_cache, *route_cache;
53 } NMIP6ManagerPrivate;
55 #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate))
57 G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
65 static guint signals[LAST_SIGNAL] = { 0 };
68 NM_IP6_DEVICE_UNCONFIGURED,
69 NM_IP6_DEVICE_GOT_LINK_LOCAL,
70 NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
71 NM_IP6_DEVICE_GOT_ADDRESS,
72 NM_IP6_DEVICE_TIMED_OUT
85 /******************************************************************/
88 NMIP6Manager *manager;
92 gboolean has_linklocal;
93 gboolean has_nonlinklocal;
96 char *disable_ip6_path;
97 gboolean disable_ip6_save_valid;
98 gint32 disable_ip6_save;
100 guint finish_addrconf_id;
101 guint config_changed_id;
103 NMIP6DeviceState state;
104 NMIP6DeviceState target_state;
105 gboolean addrconf_complete;
107 GArray *rdnss_servers;
108 guint rdnss_timeout_id;
110 GArray *dnssl_domains;
111 guint dnssl_timeout_id;
113 guint ip6flags_poll_id;
119 clear_config_changed (NMIP6Device *device)
121 if (device->config_changed_id)
122 g_source_remove (device->config_changed_id);
123 device->config_changed_id = 0;
127 nm_ip6_device_destroy (NMIP6Device *device)
129 g_return_if_fail (device != NULL);
131 /* reset the saved IPv6 value */
132 if (device->disable_ip6_save_valid) {
133 nm_utils_do_sysctl (device->disable_ip6_path,
134 device->disable_ip6_save ? "1\n" : "0\n");
137 if (device->finish_addrconf_id)
138 g_source_remove (device->finish_addrconf_id);
140 clear_config_changed (device);
142 g_free (device->iface);
143 if (device->rdnss_servers)
144 g_array_free (device->rdnss_servers, TRUE);
145 if (device->rdnss_timeout_id)
146 g_source_remove (device->rdnss_timeout_id);
147 if (device->dnssl_domains)
148 g_array_free (device->dnssl_domains, TRUE);
149 if (device->dnssl_timeout_id)
150 g_source_remove (device->dnssl_timeout_id);
151 if (device->ip6flags_poll_id)
152 g_source_remove (device->ip6flags_poll_id);
154 g_slice_free (NMIP6Device, device);
158 nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
160 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
163 g_return_val_if_fail (ifindex > 0, NULL);
165 device = g_slice_new0 (NMIP6Device);
167 nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.",
172 device->ifindex = ifindex;
173 device->iface = nm_netlink_index_to_iface (ifindex);
174 if (!device->iface) {
175 nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
180 device->manager = manager;
182 device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
184 device->dnssl_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
186 g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
188 /* and the original value of IPv6 enable/disable */
189 device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
191 g_assert (device->disable_ip6_path);
192 device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value_with_bounds (device->disable_ip6_path,
194 &device->disable_ip6_save,
200 nm_ip6_device_destroy (device);
205 nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
207 NMIP6ManagerPrivate *priv;
209 g_return_val_if_fail (manager != NULL, NULL);
210 g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
212 priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
213 return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
217 device_get_iface (NMIP6Device *device)
219 return device ? device->iface : "unknown";
223 state_to_string (NMIP6DeviceState state)
226 case NM_IP6_DEVICE_UNCONFIGURED:
227 return "unconfigured";
228 case NM_IP6_DEVICE_GOT_LINK_LOCAL:
229 return "got-link-local";
230 case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
232 case NM_IP6_DEVICE_GOT_ADDRESS:
233 return "got-address";
234 case NM_IP6_DEVICE_TIMED_OUT:
242 device_set_state (NMIP6Device *device, NMIP6DeviceState state)
244 NMIP6DeviceState oldstate;
246 g_return_if_fail (device != NULL);
248 oldstate = device->state;
249 device->state = state;
250 nm_log_dbg (LOGD_IP6, "(%s) IP6 device state: %s -> %s",
251 device_get_iface (device), state_to_string (oldstate), state_to_string (state));
254 /******************************************************************/
263 finish_addrconf (gpointer user_data)
265 CallbackInfo *info = user_data;
266 NMIP6Device *device = info->device;
267 NMIP6Manager *manager = device->manager;
270 device->finish_addrconf_id = 0;
271 device->addrconf_complete = TRUE;
272 ifindex = device->ifindex;
274 /* We're done, stop polling IPv6 flags */
275 if (device->ip6flags_poll_id) {
276 g_source_remove (device->ip6flags_poll_id);
277 device->ip6flags_poll_id = 0;
280 /* And tell listeners that addrconf is complete */
282 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
283 ifindex, info->dhcp_opts, TRUE);
285 nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
288 nm_ip6_manager_cancel_addrconf (manager, ifindex);
289 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
290 ifindex, info->dhcp_opts, FALSE);
297 emit_config_changed (gpointer user_data)
299 CallbackInfo *info = user_data;
300 NMIP6Device *device = info->device;
301 NMIP6Manager *manager = device->manager;
303 device->config_changed_id = 0;
304 g_signal_emit (manager, signals[CONFIG_CHANGED], 0,
311 static void set_rdnss_timeout (NMIP6Device *device);
314 rdnss_expired (gpointer user_data)
316 NMIP6Device *device = user_data;
317 CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
319 nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface);
321 set_rdnss_timeout (device);
322 clear_config_changed (device);
323 emit_config_changed (&info);
328 set_rdnss_timeout (NMIP6Device *device)
330 time_t expires = 0, now = time (NULL);
334 if (device->rdnss_timeout_id) {
335 g_source_remove (device->rdnss_timeout_id);
336 device->rdnss_timeout_id = 0;
339 /* Find the soonest expiration time. */
340 for (i = 0; i < device->rdnss_servers->len; i++) {
341 rdnss = &g_array_index (device->rdnss_servers, NMIP6RDNSS, i);
342 if (rdnss->expires == 0)
345 /* If the entry has already expired, remove it; the "+ 1" is
346 * because g_timeout_add_seconds() might fudge the timing a
349 if (rdnss->expires <= now + 1) {
350 char buf[INET6_ADDRSTRLEN + 1];
352 if (inet_ntop (AF_INET6, &(rdnss->addr), buf, sizeof (buf)) > 0) {
353 nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided nameserver %s",
356 g_array_remove_index (device->rdnss_servers, i--);
360 if (!expires || rdnss->expires < expires)
361 expires = rdnss->expires;
365 device->rdnss_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
371 static void set_dnssl_timeout (NMIP6Device *device);
374 dnssl_expired (gpointer user_data)
376 NMIP6Device *device = user_data;
377 CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
379 nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface);
381 set_dnssl_timeout (device);
382 clear_config_changed (device);
383 emit_config_changed (&info);
388 set_dnssl_timeout (NMIP6Device *device)
390 time_t expires = 0, now = time (NULL);
394 if (device->dnssl_timeout_id) {
395 g_source_remove (device->dnssl_timeout_id);
396 device->dnssl_timeout_id = 0;
399 /* Find the soonest expiration time. */
400 for (i = 0; i < device->dnssl_domains->len; i++) {
401 dnssl = &g_array_index (device->dnssl_domains, NMIP6DNSSL, i);
402 if (dnssl->expires == 0)
405 /* If the entry has already expired, remove it; the "+ 1" is
406 * because g_timeout_add_seconds() might fudge the timing a
409 if (dnssl->expires <= now + 1) {
410 nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided domain %s",
411 device->iface, dnssl->domain);
412 g_array_remove_index (device->dnssl_domains, i--);
416 if (!expires || dnssl->expires < expires)
417 expires = dnssl->expires;
421 device->dnssl_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
427 static CallbackInfo *
428 callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
432 info = g_malloc0 (sizeof (CallbackInfo));
433 info->device = device;
434 info->dhcp_opts = dhcp_opts;
435 info->success = success;
440 check_addresses (NMIP6Device *device)
442 NMIP6Manager *manager = device->manager;
443 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
444 struct rtnl_addr *rtnladdr;
445 struct nl_addr *nladdr;
446 struct in6_addr *addr;
448 /* Reset address information */
449 device->has_linklocal = FALSE;
450 device->has_nonlinklocal = FALSE;
452 /* Look for any IPv6 addresses the kernel may have set for the device */
453 for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
455 rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) {
456 char buf[INET6_ADDRSTRLEN];
458 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
461 nladdr = rtnl_addr_get_local (rtnladdr);
462 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
465 addr = nl_addr_get_binary_addr (nladdr);
467 if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) {
468 nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d",
470 rtnl_addr_get_prefixlen (rtnladdr));
473 if (IN6_IS_ADDR_LINKLOCAL (addr)) {
474 if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
475 device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL);
476 device->has_linklocal = TRUE;
478 if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
479 device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS);
480 device->has_nonlinklocal = TRUE;
484 /* There might be a LL address hanging around on the interface from
485 * before in the initial run, but if it goes away later, make sure we
486 * regress from GOT_LINK_LOCAL back to UNCONFIGURED.
488 if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal)
489 device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED);
491 nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)",
492 device->iface, state_to_string (device->state));
496 check_ra_flags (NMIP6Device *device)
498 device->dhcp_opts = IP6_DHCP_OPT_NONE;
500 /* We only care about router advertisements if we want a real IPv6 address */
501 if ( (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
502 && (device->ra_flags & IF_RA_RCVD)) {
504 if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
505 device_set_state (device, NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT);
507 if (device->ra_flags & IF_RA_MANAGED) {
508 device->dhcp_opts = IP6_DHCP_OPT_MANAGED;
509 nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
510 } else if (device->ra_flags & IF_RA_OTHERCONF) {
511 device->dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
512 nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
515 nm_log_dbg (LOGD_IP6, "(%s): router advertisement checked (state %s)",
516 device->iface, state_to_string (device->state));
520 check_addrconf_complete (NMIP6Device *device)
524 if (!device->addrconf_complete) {
525 /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
526 * we don't bother waiting for the device's target state to be reached
527 * when the RA requests managed mode.
529 if ( (device->state >= device->target_state)
530 || (device->dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
531 /* device->finish_addrconf_id may currently be a timeout
532 * rather than an idle, so we remove the existing source.
534 if (device->finish_addrconf_id)
535 g_source_remove (device->finish_addrconf_id);
537 nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)",
538 device->iface, state_to_string (device->state),
541 info = callback_info_new (device, device->dhcp_opts, TRUE);
542 device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
545 (GDestroyNotify) g_free);
548 if (!device->config_changed_id) {
549 gboolean success = TRUE;
551 /* If for some reason an RA-provided address disappeared, we need
552 * to make sure we fail the connection as it's no longer valid.
554 if ( (device->state == NM_IP6_DEVICE_GOT_ADDRESS)
555 && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
556 && !device->has_nonlinklocal) {
557 nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer found",
562 info = callback_info_new (device, device->dhcp_opts, success);
563 device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
566 (GDestroyNotify) g_free);
570 nm_log_dbg (LOGD_IP6, "(%s): dhcp_opts checked (state %s)",
571 device->iface, state_to_string (device->state));
575 nm_ip6_device_sync_from_netlink (NMIP6Device *device)
577 nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
578 device->iface, device->ra_flags,
579 state_to_string (device->state),
580 state_to_string (device->target_state));
582 check_addresses (device);
583 check_ra_flags (device);
584 check_addrconf_complete (device);
588 ref_object (struct nl_object *obj, void *data)
590 struct nl_object **out = data;
597 dump_address_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_addr *rtnladdr)
600 struct nl_addr *addr;
601 char addr_str[40] = "none";
603 event = hdr->nlmsg_type == RTM_NEWADDR ? "new" : "lost";
604 addr = rtnl_addr_get_local (rtnladdr);
606 nl_addr2str (addr, addr_str, 40);
608 nm_log_dbg (LOGD_IP6, "(%s) %s address: %s", device_get_iface (device), event, addr_str);
612 dump_route_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_route *rtnlroute)
616 char dst_str[40] = "none";
617 struct nl_addr *gateway;
618 char gateway_str[40] = "none";
620 event = hdr->nlmsg_type == RTM_NEWROUTE ? "new" : "lost";
621 dst = rtnl_route_get_dst (rtnlroute);
622 gateway = rtnl_route_get_gateway (rtnlroute);
624 nl_addr2str (dst, dst_str, 40);
626 nl_addr2str (gateway, gateway_str, 40);
628 nm_log_dbg (LOGD_IP6, "(%s) %s route: %s via %s",device_get_iface (device), event, dst_str, gateway_str);
632 process_address_change (NMIP6Manager *manager, struct nl_msg *msg)
634 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
636 struct nlmsghdr *hdr;
637 struct rtnl_addr *rtnladdr;
640 hdr = nlmsg_hdr (msg);
642 nl_msg_parse (msg, ref_object, &rtnladdr);
644 nm_log_dbg (LOGD_IP6, "error processing netlink new/del address message");
648 device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
650 old_size = nl_cache_nitems (priv->addr_cache);
651 nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL);
653 /* The kernel will re-notify us of automatically-added addresses
654 * every time it gets another router advertisement. We only want
655 * to notify higher levels if we actually changed something.
657 nm_log_dbg (LOGD_IP6, "(%s): address cache size: %d -> %d:",
658 device_get_iface (device), old_size, nl_cache_nitems (priv->addr_cache));
659 dump_address_change (device, hdr, rtnladdr);
660 rtnl_addr_put (rtnladdr);
661 if (nl_cache_nitems (priv->addr_cache) == old_size)
668 process_route_change (NMIP6Manager *manager, struct nl_msg *msg)
670 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
672 struct nlmsghdr *hdr;
673 struct rtnl_route *rtnlroute;
676 hdr = nlmsg_hdr (msg);
678 nl_msg_parse (msg, ref_object, &rtnlroute);
680 nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message");
684 device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
686 old_size = nl_cache_nitems (priv->route_cache);
687 nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
689 /* As above in process_address_change */
690 nm_log_dbg (LOGD_IP6, "(%s): route cache size: %d -> %d:",
691 device_get_iface (device), old_size, nl_cache_nitems (priv->route_cache));
692 dump_route_change (device, hdr, rtnlroute);
693 rtnl_route_put (rtnlroute);
694 if (nl_cache_nitems (priv->route_cache) == old_size)
700 /* RDNSS parsing code based on rdnssd, Copyright 2007 Pierre Ynard,
701 * Rémi Denis-Courmont. GPLv2/3
704 #define ND_OPT_RDNSS 25
705 #define ND_OPT_DNSSL 31
707 struct nd_opt_rdnss {
708 uint8_t nd_opt_rdnss_type;
709 uint8_t nd_opt_rdnss_len;
710 uint16_t nd_opt_rdnss_reserved1;
711 uint32_t nd_opt_rdnss_lifetime;
712 /* followed by one or more IPv6 addresses */
713 } __attribute__ ((packed));
715 struct nd_opt_dnssl {
716 uint8_t nd_opt_dnssl_type;
717 uint8_t nd_opt_dnssl_len;
718 uint16_t nd_opt_dnssl_reserved1;
719 uint32_t nd_opt_dnssl_lifetime;
720 /* followed by one or more suffixes */
721 } __attribute__ ((packed));
724 process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
727 struct nd_opt_rdnss *rdnss_opt;
728 time_t now = time (NULL);
729 struct in6_addr *addr;
731 NMIP6RDNSS server, *cur_server;
732 gboolean changed = FALSE;
735 opt_len = opt->nd_opt_len;
737 if (opt_len < 3 || (opt_len & 1) == 0)
740 rdnss_opt = (struct nd_opt_rdnss *) opt;
742 new_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
744 /* Pad the DNS server expiry somewhat to give a bit of slack in cases
745 * where one RA gets lost or something (which can happen on unreliable
746 * links like WiFi where certain types of frames are not retransmitted).
747 * Note that 0 has special meaning and is therefore not adjusted.
749 server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
750 if (server.expires > 0)
751 if (server.expires < 7200)
752 server.expires = 7200;
753 server.expires += now;
755 for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
756 char buf[INET6_ADDRSTRLEN + 1];
758 if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf))) {
759 nm_log_warn (LOGD_IP6, "(%s): received invalid RA-provided nameserver", device->iface);
763 /* Update the cached timeout if we already saw this server */
764 for (i = 0; i < device->rdnss_servers->len; i++) {
765 cur_server = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
767 if (!IN6_ARE_ADDR_EQUAL (addr, &cur_server->addr))
770 cur_server->expires = server.expires;
772 if (server.expires > 0) {
773 nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided nameserver %s (expires in %ld seconds)",
775 server.expires - now);
779 nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided nameserver %s on router request",
782 g_array_remove_index (device->rdnss_servers, i);
787 if (server.expires == 0)
789 if (i < device->rdnss_servers->len)
792 nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %ld seconds)",
793 device->iface, buf, server.expires - now);
796 g_array_append_val (new_servers, server);
799 /* New servers must be added in the order they are listed in the
800 * RA option and before any existing servers.
802 * Note: This is the place to remove servers if we want to cap the
803 * number of resolvers. The RFC states that the one to expire
804 * first of the existing servers should be removed.
806 if (new_servers->len) {
807 g_array_prepend_vals (device->rdnss_servers,
808 new_servers->data, new_servers->len);
812 g_array_free (new_servers, TRUE);
814 /* Timeouts may have changed even if IPs didn't */
815 set_rdnss_timeout (device);
821 parse_dnssl_domain (const unsigned char *buffer, size_t maxlen)
823 static char domain[256];
836 if (label_len > maxlen)
838 if ((sizeof (domain) - strlen (domain)) < (label_len + 2))
841 if (domain[0] != '\0')
842 strcat (domain, ".");
843 strncat (domain, (const char *)buffer, label_len);
852 process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
855 struct nd_opt_dnssl *dnssl_opt;
856 unsigned char *opt_ptr;
857 time_t now = time (NULL);
859 NMIP6DNSSL domain, *cur_domain;
863 opt_len = opt->nd_opt_len;
868 dnssl_opt = (struct nd_opt_dnssl *) opt;
870 opt_ptr = (unsigned char *)(dnssl_opt + 1);
871 opt_len = (opt_len - 1) * 8; /* prefer bytes for later handling */
873 new_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
877 /* Pad the DNS server expiry somewhat to give a bit of slack in cases
878 * where one RA gets lost or something (which can happen on unreliable
879 * links like wifi where certain types of frames are not retransmitted).
880 * Note that 0 has special meaning and is therefore not adjusted.
882 domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
883 if (domain.expires > 0)
884 if (domain.expires < 7200)
885 domain.expires = 7200;
886 domain.expires += now;
889 const char *domain_str;
891 domain_str = parse_dnssl_domain (opt_ptr, opt_len);
892 if (domain_str == NULL) {
893 nm_log_dbg (LOGD_IP6, "(%s): invalid DNSSL option, parsing aborted",
898 /* The DNSSL encoding of domains happen to occupy the same size
899 * as the length of the resulting string, including terminating
901 opt_ptr += strlen (domain_str) + 1;
902 opt_len -= strlen (domain_str) + 1;
904 /* Ignore empty domains. They're probably just padding... */
905 if (domain_str[0] == '\0')
908 /* Update cached domain information if we've seen this domain before */
909 for (i = 0; i < device->dnssl_domains->len; i++) {
910 cur_domain = &(g_array_index (device->dnssl_domains, NMIP6DNSSL, i));
912 if (strcmp (domain_str, cur_domain->domain) != 0)
915 cur_domain->expires = domain.expires;
917 if (domain.expires > 0) {
918 nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided domain %s (expires in %ld seconds)",
919 device->iface, domain_str,
920 domain.expires - now);
924 nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided domain %s on router request",
925 device->iface, domain_str);
927 g_array_remove_index (device->dnssl_domains, i);
932 if (domain.expires == 0)
934 if (i < device->dnssl_domains->len)
937 nm_log_dbg (LOGD_IP6, "(%s): found RA-provided domain %s (expires in %ld seconds)",
938 device->iface, domain_str, domain.expires - now);
940 g_assert (strlen (domain_str) < sizeof (domain.domain));
941 strcpy (domain.domain, domain_str);
942 g_array_append_val (new_domains, domain);
945 /* New domains must be added in the order they are listed in the
946 * RA option and before any existing domains.
948 * Note: This is the place to remove domains if we want to cap the
949 * number of domains. The RFC states that the one to expire
950 * first of the existing domains should be removed.
952 if (new_domains->len) {
953 g_array_prepend_vals (device->dnssl_domains,
954 new_domains->data, new_domains->len);
958 g_array_free (new_domains, TRUE);
960 /* Timeouts may have changed even if domains didn't */
961 set_dnssl_timeout (device);
967 process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
970 struct nduseroptmsg *ndmsg;
971 struct nd_opt_hdr *opt;
973 gboolean changed = FALSE;
975 nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message");
977 ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg));
979 if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof (*ndmsg)) ||
980 nlmsg_datalen (nlmsg_hdr (msg)) <
981 (ndmsg->nduseropt_opts_len + sizeof (*ndmsg))) {
982 nm_log_dbg (LOGD_IP6, "ignoring invalid nduseropt message");
986 if (ndmsg->nduseropt_family != AF_INET6 ||
987 ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
988 ndmsg->nduseropt_icmp_code != 0) {
989 nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message");
993 device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex);
995 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
999 opt = (struct nd_opt_hdr *) (ndmsg + 1);
1000 opts_len = ndmsg->nduseropt_opts_len;
1002 while (opts_len >= sizeof (struct nd_opt_hdr)) {
1003 size_t nd_opt_len = opt->nd_opt_len;
1005 if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
1008 switch (opt->nd_opt_type) {
1010 changed = process_nduseropt_rdnss (device, opt);
1013 changed = process_nduseropt_dnssl (device, opt);
1017 opts_len -= opt->nd_opt_len << 3;
1018 opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3));
1027 static struct nla_policy link_policy[IFLA_MAX + 1] = {
1028 [IFLA_PROTINFO] = { .type = NLA_NESTED },
1031 static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
1032 [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
1036 ra_flags_to_string (guint32 ra_flags)
1038 GString *s = g_string_sized_new (20);
1040 g_string_append (s, " (");
1041 if (ra_flags & IF_RS_SENT)
1042 g_string_append_c (s, 'S');
1044 if (ra_flags & IF_RA_RCVD)
1045 g_string_append_c (s, 'R');
1047 if (ra_flags & IF_RA_OTHERCONF)
1048 g_string_append_c (s, 'O');
1050 if (ra_flags & IF_RA_MANAGED)
1051 g_string_append_c (s, 'M');
1053 g_string_append_c (s, ')');
1054 return g_string_free (s, FALSE);
1057 static NMIP6Device *
1058 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
1060 struct nlmsghdr *hdr = nlmsg_hdr (msg);
1061 struct ifinfomsg *ifi;
1062 NMIP6Device *device;
1063 struct nlattr *tb[IFLA_MAX + 1];
1064 struct nlattr *pi[IFLA_INET6_MAX + 1];
1066 char *flags_str = NULL;
1068 /* FIXME: we have to do this manually for now since libnl doesn't yet
1069 * support the IFLA_PROTINFO attribute of NEWLINK messages. When it does,
1070 * we can get rid of this function and just grab IFLA_PROTINFO from
1071 * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
1074 err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
1076 nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message "
1077 "while parsing PROTINFO attribute");
1081 ifi = nlmsg_data (hdr);
1082 if (ifi->ifi_family != AF_INET6) {
1083 nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family);
1087 device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
1088 if (!device || device->addrconf_complete) {
1089 nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
1090 device ? device->iface : "(none)");
1094 if (!tb[IFLA_PROTINFO]) {
1095 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface);
1099 err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
1101 nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface);
1104 if (!pi[IFLA_INET6_FLAGS]) {
1105 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface);
1109 device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
1111 if (nm_logging_level_enabled (LOGL_DEBUG))
1112 flags_str = ra_flags_to_string (device->ra_flags);
1113 nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X%s",
1114 device->iface, device->ra_flags, flags_str ? flags_str : "");
1121 netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
1123 NMIP6Manager *manager = (NMIP6Manager *) user_data;
1124 NMIP6Device *device;
1125 struct nlmsghdr *hdr;
1127 hdr = nlmsg_hdr (msg);
1128 nm_log_dbg (LOGD_HW, "netlink event type %d", hdr->nlmsg_type);
1129 switch (hdr->nlmsg_type) {
1132 device = process_address_change (manager, msg);
1136 device = process_route_change (manager, msg);
1138 case RTM_NEWNDUSEROPT:
1139 device = process_nduseropt (manager, msg);
1142 device = process_newlink (manager, msg);
1149 nm_ip6_device_sync_from_netlink (device);
1154 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
1156 NMSettingIP6Config *s_ip6,
1157 const char *accept_ra_path)
1159 NMIP6ManagerPrivate *priv;
1160 NMIP6Device *device;
1161 const char *method = NULL;
1163 g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), FALSE);
1164 g_return_val_if_fail (ifindex > 0, FALSE);
1166 priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1168 device = nm_ip6_device_new (manager, ifindex);
1169 g_return_val_if_fail (device != NULL, FALSE);
1170 g_return_val_if_fail ( strchr (device->iface, '/') == NULL
1171 && strcmp (device->iface, "all") != 0
1172 && strcmp (device->iface, "default") != 0,
1176 method = nm_setting_ip6_config_get_method (s_ip6);
1178 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
1180 /* Establish target state and turn router advertisement acceptance on or off */
1181 if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
1182 device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
1183 nm_utils_do_sysctl (accept_ra_path, "0\n");
1185 device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
1186 nm_utils_do_sysctl (accept_ra_path, "2\n");
1193 poll_ip6_flags (gpointer user_data)
1195 nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL);
1200 nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
1202 NMIP6ManagerPrivate *priv;
1203 NMIP6Device *device;
1206 g_return_if_fail (NM_IS_IP6_MANAGER (manager));
1207 g_return_if_fail (ifindex > 0);
1209 priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1211 device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
1212 g_return_if_fail (device != NULL);
1214 nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface);
1216 device->addrconf_complete = FALSE;
1217 device->ra_flags = 0;
1219 /* Set up a timeout on the transaction to kill it after the timeout */
1220 info = callback_info_new (device, 0, FALSE);
1221 device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
1225 (GDestroyNotify) g_free);
1227 /* Bounce IPv6 on the interface to ensure the kernel will start looking for
1228 * new RAs; there doesn't seem to be a better way to do this right now.
1230 if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) {
1231 nm_utils_do_sysctl (device->disable_ip6_path, "1\n");
1233 nm_utils_do_sysctl (device->disable_ip6_path, "0\n");
1236 device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor);
1238 /* Kick off the initial IPv6 flags request */
1239 nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
1241 /* Sync flags, etc, from netlink; this will also notice if the
1242 * device is already fully configured and schedule the
1243 * ADDRCONF_COMPLETE signal in that case.
1245 nm_ip6_device_sync_from_netlink (device);
1249 nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex)
1251 g_return_if_fail (NM_IS_IP6_MANAGER (manager));
1252 g_return_if_fail (ifindex > 0);
1254 g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices,
1255 GINT_TO_POINTER (ifindex));
1258 #define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m))
1259 #define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m))
1261 #define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m))
1262 #define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m))
1265 nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
1267 NMIP6ManagerPrivate *priv;
1268 NMIP6Device *device;
1269 NMIP6Config *config;
1270 struct rtnl_addr *rtnladdr;
1271 struct nl_addr *nladdr;
1272 struct in6_addr *addr;
1273 NMIP6Address *ip6addr;
1274 struct rtnl_route *rtnlroute;
1275 struct nl_addr *nldest, *nlgateway;
1276 struct in6_addr *dest, *gateway;
1278 NMIP6Route *ip6route;
1281 g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
1282 g_return_val_if_fail (ifindex > 0, NULL);
1284 priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1286 device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
1287 GINT_TO_POINTER (ifindex));
1289 nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
1293 config = nm_ip6_config_new ();
1295 nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
1300 /* Make sure we refill the route and address caches, otherwise we won't get
1301 * up-to-date information here since the netlink route/addr change messages
1302 * may be lagging a bit.
1304 nl_cache_refill (priv->nlh, priv->route_cache);
1305 nl_cache_refill (priv->nlh, priv->addr_cache);
1308 for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
1309 /* Make sure it's an IPv6 route for this device */
1310 if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
1312 if (rtnl_route_get_family (rtnlroute) != AF_INET6)
1315 nldest = rtnl_route_get_dst (rtnlroute);
1316 if (!nldest || nl_addr_get_family (nldest) != AF_INET6)
1318 dest = nl_addr_get_binary_addr (nldest);
1320 nlgateway = rtnl_route_get_gateway (rtnlroute);
1321 if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6)
1323 gateway = nl_addr_get_binary_addr (nlgateway);
1325 if (rtnl_route_get_dst_len (rtnlroute) == 0) {
1326 /* Default gateway route; don't add to normal routes but to each address */
1327 if (!nm_ip6_config_get_gateway (config)) {
1328 nm_ip6_config_set_gateway (config, gateway);
1333 /* Also ignore link-local routes where the destination and gateway are
1334 * the same, which apparently get added by the kernel but return -EINVAL
1335 * when we try to add them via netlink.
1337 if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway))
1340 ip6route = nm_ip6_route_new ();
1341 nm_ip6_route_set_dest (ip6route, dest);
1342 nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
1343 nm_ip6_route_set_next_hop (ip6route, gateway);
1344 rtnl_route_get_metric(rtnlroute, 1, &metric);
1345 if (metric != UINT_MAX)
1346 nm_ip6_route_set_metric (ip6route, metric);
1347 nm_ip6_config_take_route (config, ip6route);
1351 for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
1352 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
1355 nladdr = rtnl_addr_get_local (rtnladdr);
1356 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
1359 addr = nl_addr_get_binary_addr (nladdr);
1360 ip6addr = nm_ip6_address_new ();
1361 nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
1362 nm_ip6_address_set_address (ip6addr, addr);
1363 nm_ip6_config_take_address (config, ip6addr);
1364 gateway = nm_ip6_config_get_gateway (config);
1366 nm_ip6_address_set_gateway (ip6addr, gateway);
1369 /* Add DNS servers */
1370 if (device->rdnss_servers) {
1371 NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);
1373 for (i = 0; i < device->rdnss_servers->len; i++)
1374 nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
1377 /* Add DNS domains */
1378 if (device->dnssl_domains) {
1379 NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data);
1381 for (i = 0; i < device->dnssl_domains->len; i++)
1382 nm_ip6_config_add_domain (config, dnssl[i].domain);
1388 /******************************************************************/
1390 static NMIP6Manager *
1391 nm_ip6_manager_new (void)
1393 NMIP6Manager *manager;
1394 NMIP6ManagerPrivate *priv;
1396 manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
1397 priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1399 if (!priv->devices) {
1400 nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
1401 g_object_unref (manager);
1408 static NMIP6Manager *singleton = NULL;
1411 nm_ip6_manager_get (void)
1414 singleton = nm_ip6_manager_new ();
1415 g_assert (singleton);
1417 g_object_ref (singleton);
1423 nm_ip6_manager_init (NMIP6Manager *manager)
1425 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1427 priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1429 (GDestroyNotify) nm_ip6_device_destroy);
1431 priv->monitor = nm_netlink_monitor_get ();
1432 nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
1433 nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
1434 nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_ROUTE, NULL);
1435 nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
1436 nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
1438 priv->netlink_id = g_signal_connect (priv->monitor, "notification",
1439 G_CALLBACK (netlink_notification), manager);
1441 priv->nlh = nm_netlink_get_default_handle ();
1442 rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
1443 g_warn_if_fail (priv->addr_cache != NULL);
1444 rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
1445 g_warn_if_fail (priv->route_cache != NULL);
1449 finalize (GObject *object)
1451 NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
1453 g_signal_handler_disconnect (priv->monitor, priv->netlink_id);
1455 g_hash_table_destroy (priv->devices);
1456 g_object_unref (priv->monitor);
1457 nl_cache_free (priv->addr_cache);
1458 nl_cache_free (priv->route_cache);
1462 G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
1466 nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
1468 GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
1470 g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
1472 /* virtual methods */
1473 object_class->finalize = finalize;
1476 signals[ADDRCONF_COMPLETE] =
1477 g_signal_new ("addrconf-complete",
1478 G_OBJECT_CLASS_TYPE (object_class),
1480 G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
1482 _nm_marshal_VOID__INT_UINT_BOOLEAN,
1483 G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
1485 signals[CONFIG_CHANGED] =
1486 g_signal_new ("config-changed",
1487 G_OBJECT_CLASS_TYPE (object_class),
1489 G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
1491 _nm_marshal_VOID__INT_UINT_BOOLEAN,
1492 G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);