ip6: restructure RDNSS code to be RFC compliant (bgo #637075)
[NetworkManager.git] / src / ip6-manager / nm-ip6-manager.c
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
3  *
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)
7  * any later version.
8  *
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.
13  *
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.
17  *
18  * Copyright (C) 2009 - 2010 Red Hat, Inc.
19  */
20
21 #include <errno.h>
22 #include <netinet/icmp6.h>
23
24 #include <netlink/route/addr.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink/route/route.h>
27
28 #include "nm-ip6-manager.h"
29 #include "nm-netlink-monitor.h"
30 #include "NetworkManagerUtils.h"
31 #include "nm-marshal.h"
32 #include "nm-logging.h"
33 #include "nm-system.h"
34
35 /* Pre-DHCP addrconf timeout, in seconds */
36 #define NM_IP6_TIMEOUT 20
37
38 /* FIXME? Stolen from the kernel sources */
39 #define IF_RA_OTHERCONF 0x80
40 #define IF_RA_MANAGED   0x40
41 #define IF_RA_RCVD      0x20
42 #define IF_RS_SENT      0x10
43
44 typedef struct {
45         NMNetlinkMonitor *monitor;
46         GHashTable *devices;
47
48         struct nl_handle *nlh;
49         struct nl_cache *addr_cache, *route_cache;
50
51         guint netlink_id;
52 } NMIP6ManagerPrivate;
53
54 #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate))
55
56 G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
57
58 enum {
59         ADDRCONF_COMPLETE,
60         CONFIG_CHANGED,
61         LAST_SIGNAL
62 };
63
64 static guint signals[LAST_SIGNAL] = { 0 };
65
66 typedef enum {
67         NM_IP6_DEVICE_UNCONFIGURED,
68         NM_IP6_DEVICE_GOT_LINK_LOCAL,
69         NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
70         NM_IP6_DEVICE_GOT_ADDRESS,
71         NM_IP6_DEVICE_TIMED_OUT
72 } NMIP6DeviceState;
73
74 typedef struct {
75         struct in6_addr addr;
76         time_t expires;
77 } NMIP6RDNSS;
78
79 /******************************************************************/
80
81 typedef struct {
82         NMIP6Manager *manager;
83         char *iface;
84         int ifindex;
85
86         char *disable_ip6_path;
87         gboolean disable_ip6_save_valid;
88         guint32 disable_ip6_save;
89
90         guint finish_addrconf_id;
91         guint config_changed_id;
92
93         NMIP6DeviceState state;
94         NMIP6DeviceState target_state;
95         gboolean addrconf_complete;
96
97         GArray *rdnss_servers;
98         guint rdnss_timeout_id;
99
100         guint ip6flags_poll_id;
101
102         guint32 ra_flags;
103 } NMIP6Device;
104
105 static void
106 nm_ip6_device_destroy (NMIP6Device *device)
107 {
108         g_return_if_fail (device != NULL);
109
110         /* reset the saved IPv6 value */
111         if (device->disable_ip6_save_valid) {
112                 nm_utils_do_sysctl (device->disable_ip6_path,
113                                     device->disable_ip6_save ? "1\n" : "0\n");
114         }
115
116         if (device->finish_addrconf_id)
117                 g_source_remove (device->finish_addrconf_id);
118         if (device->config_changed_id)
119                 g_source_remove (device->config_changed_id);
120         g_free (device->iface);
121         if (device->rdnss_servers)
122                 g_array_free (device->rdnss_servers, TRUE);
123         if (device->rdnss_timeout_id)
124                 g_source_remove (device->rdnss_timeout_id);
125         if (device->ip6flags_poll_id)
126                 g_source_remove (device->ip6flags_poll_id);
127
128         g_slice_free (NMIP6Device, device);
129 }
130
131 static NMIP6Device *
132 nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
133 {
134         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
135         NMIP6Device *device;
136
137         g_return_val_if_fail (ifindex > 0, NULL);
138
139         device = g_slice_new0 (NMIP6Device);
140         if (!device) {
141                 nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.",
142                             ifindex);
143                 return NULL;
144         }
145
146         device->ifindex = ifindex;
147         device->iface = g_strdup (nm_netlink_index_to_iface (ifindex));
148         if (!device->iface) {
149                 nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
150                             ifindex);
151                 goto error;
152         }
153
154         device->manager = manager;
155
156         device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
157
158         g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
159
160         /* and the original value of IPv6 enable/disable */
161         device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
162                                                     device->iface);
163         g_assert (device->disable_ip6_path);
164         device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value (device->disable_ip6_path,
165                                                                           device->iface,
166                                                                           &device->disable_ip6_save);
167
168         return device;
169
170 error:
171         nm_ip6_device_destroy (device);
172         return NULL;
173 }
174
175 static NMIP6Device *
176 nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
177 {
178         NMIP6ManagerPrivate *priv;
179
180         g_return_val_if_fail (manager != NULL, NULL);
181         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
182
183         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
184         return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
185 }
186
187 /******************************************************************/
188
189 typedef struct {
190         NMIP6Device *device;
191         guint dhcp_opts;
192         gboolean success;
193 } CallbackInfo;
194
195 static gboolean
196 finish_addrconf (gpointer user_data)
197 {
198         CallbackInfo *info = user_data;
199         NMIP6Device *device = info->device;
200         NMIP6Manager *manager = device->manager;
201         int ifindex;
202
203         device->finish_addrconf_id = 0;
204         device->addrconf_complete = TRUE;
205         ifindex = device->ifindex;
206
207         /* We're done, stop polling IPv6 flags */
208         if (device->ip6flags_poll_id) {
209                 g_source_remove (device->ip6flags_poll_id);
210                 device->ip6flags_poll_id = 0;
211         }
212
213         /* And tell listeners that addrconf is complete */
214         if (info->success) {
215                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
216                                ifindex, info->dhcp_opts, TRUE);
217         } else {
218                 nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
219                              device->iface);
220
221                 nm_ip6_manager_cancel_addrconf (manager, ifindex);
222                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
223                                ifindex, info->dhcp_opts, FALSE);
224         }
225
226         return FALSE;
227 }
228
229 static gboolean
230 emit_config_changed (gpointer user_data)
231 {
232         CallbackInfo *info = user_data;
233         NMIP6Device *device = info->device;
234         NMIP6Manager *manager = device->manager;
235
236         device->config_changed_id = 0;
237         g_signal_emit (manager, signals[CONFIG_CHANGED], 0,
238                        device->ifindex,
239                        info->dhcp_opts,
240                        info->success);
241         return FALSE;
242 }
243
244 static void set_rdnss_timeout (NMIP6Device *device);
245
246 static gboolean
247 rdnss_expired (gpointer user_data)
248 {
249         NMIP6Device *device = user_data;
250         CallbackInfo info = { device, IP6_DHCP_OPT_NONE };
251
252         nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface);
253
254         set_rdnss_timeout (device);
255         emit_config_changed (&info);
256         return FALSE;
257 }
258
259 static void
260 set_rdnss_timeout (NMIP6Device *device)
261 {
262         time_t expires = 0, now = time (NULL);
263         NMIP6RDNSS *rdnss;
264         int i;
265
266         if (device->rdnss_timeout_id) {
267                 g_source_remove (device->rdnss_timeout_id);
268                 device->rdnss_timeout_id = 0;
269         }
270
271         /* Find the soonest expiration time. */
272         for (i = 0; i < device->rdnss_servers->len; i++) {
273                 rdnss = &g_array_index (device->rdnss_servers, NMIP6RDNSS, i);
274                 if (rdnss->expires == 0)
275                         continue;
276
277                 /* If the entry has already expired, remove it; the "+ 1" is
278                  * because g_timeout_add_seconds() might fudge the timing a
279                  * bit.
280                  */
281                 if (rdnss->expires <= now + 1) {
282                         char buf[INET6_ADDRSTRLEN + 1];
283
284                         if (inet_ntop (AF_INET6, &(rdnss->addr), buf, sizeof (buf)) > 0) {
285                                 nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided nameserver %s",
286                                             device->iface, buf);
287                         }
288                         g_array_remove_index (device->rdnss_servers, i--);
289                         continue;
290                 }
291
292                 if (!expires || rdnss->expires < expires)
293                         expires = rdnss->expires;
294         }
295
296         if (expires) {
297                 device->rdnss_timeout_id = g_timeout_add_seconds (expires - now,
298                                                                                                                   rdnss_expired,
299                                                                                                                   device);
300         }
301 }
302
303 static CallbackInfo *
304 callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
305 {
306         CallbackInfo *info;
307
308         info = g_malloc0 (sizeof (CallbackInfo));
309         info->device = device;
310         info->dhcp_opts = dhcp_opts;
311         info->success = success;
312         return info;
313 }
314
315 static const char *
316 state_to_string (NMIP6DeviceState state)
317 {
318         switch (state) {
319         case NM_IP6_DEVICE_UNCONFIGURED:
320                 return "unconfigured";
321         case NM_IP6_DEVICE_GOT_LINK_LOCAL:
322                 return "got-link-local";
323         case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
324                 return "got-ra";
325         case NM_IP6_DEVICE_GOT_ADDRESS:
326                 return "got-address";
327         case NM_IP6_DEVICE_TIMED_OUT:
328                 return "timed-out";
329         default:
330                 return "unknown";
331         }
332 }
333
334 static void
335 nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
336 {
337         NMIP6Manager *manager = device->manager;
338         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
339         struct rtnl_addr *rtnladdr;
340         struct nl_addr *nladdr;
341         struct in6_addr *addr;
342         CallbackInfo *info;
343         guint dhcp_opts = IP6_DHCP_OPT_NONE;
344         gboolean found_linklocal = FALSE, found_other = FALSE;
345
346         nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
347                     device->iface, device->ra_flags,
348                     state_to_string (device->state),
349                     state_to_string (device->target_state));
350
351         /* Look for any IPv6 addresses the kernel may have set for the device */
352         for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
353                  rtnladdr;
354                  rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) {
355                 char buf[INET6_ADDRSTRLEN];
356
357                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
358                         continue;
359
360                 nladdr = rtnl_addr_get_local (rtnladdr);
361                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
362                         continue;
363
364                 addr = nl_addr_get_binary_addr (nladdr);
365
366                 if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) {
367                         nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s",
368                                     device->iface, buf);
369                 }
370
371                 if (IN6_IS_ADDR_LINKLOCAL (addr)) {
372                         if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
373                                 device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
374                         found_linklocal = TRUE;
375                 } else {
376                         if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
377                                 device->state = NM_IP6_DEVICE_GOT_ADDRESS;
378                         found_other = TRUE;
379                 }
380         }
381
382         /* There might be a LL address hanging around on the interface from
383          * before in the initial run, but if it goes away later, make sure we
384          * regress from GOT_LINK_LOCAL back to UNCONFIGURED.
385          */
386         if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal)
387                 device->state = NM_IP6_DEVICE_UNCONFIGURED;
388
389         nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)",
390                     device->iface, state_to_string (device->state));
391
392         /* We only care about router advertisements if we want a real IPv6 address */
393         if (   (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
394             && (device->ra_flags & IF_RA_RCVD)) {
395
396                 if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
397                         device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
398
399                 if (device->ra_flags & IF_RA_MANAGED) {
400                         dhcp_opts = IP6_DHCP_OPT_MANAGED;
401                         nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
402                 } else if (device->ra_flags & IF_RA_OTHERCONF) {
403                         dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
404                         nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
405                 }
406         }
407
408         if (!device->addrconf_complete) {
409                 /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
410                  * we don't bother waiting for the device's target state to be reached
411                  * when the RA requests managed mode.
412                  */
413                 if (   (device->state >= device->target_state)
414                     || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
415                         /* device->finish_addrconf_id may currently be a timeout
416                          * rather than an idle, so we remove the existing source.
417                          */
418                         if (device->finish_addrconf_id)
419                                 g_source_remove (device->finish_addrconf_id);
420
421                         nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)",
422                                     device->iface, state_to_string (device->state),
423                                     dhcp_opts);
424
425                         info = callback_info_new (device, dhcp_opts, TRUE);
426                         device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
427                                                                       finish_addrconf,
428                                                                       info,
429                                                                       (GDestroyNotify) g_free);
430                 }
431         } else if (config_changed) {
432                 if (!device->config_changed_id) {
433                         gboolean success = TRUE;
434
435                         /* If for some reason an RA-provided address disappeared, we need
436                          * to make sure we fail the connection as it's no longer valid.
437                          */
438                         if (   (device->state == NM_IP6_DEVICE_GOT_ADDRESS)
439                             && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
440                             && !found_other) {
441                                 nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid",
442                                             device->iface);
443                                 success = FALSE;
444                         }
445
446                         info = callback_info_new (device, dhcp_opts, success);
447                         device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
448                                                                      emit_config_changed,
449                                                                      info,
450                                                                      (GDestroyNotify) g_free);
451                 }
452         }
453 }
454
455 static void
456 ref_object (struct nl_object *obj, void *data)
457 {
458         struct nl_object **out = data;
459
460         nl_object_get (obj);
461         *out = obj;
462 }
463
464 static NMIP6Device *
465 process_addr (NMIP6Manager *manager, struct nl_msg *msg)
466 {
467         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
468         NMIP6Device *device;
469         struct rtnl_addr *rtnladdr;
470         int old_size;
471
472         nm_log_dbg (LOGD_IP6, "processing netlink new/del address message");
473
474         rtnladdr = NULL;
475         nl_msg_parse (msg, ref_object, &rtnladdr);
476         if (!rtnladdr) {
477                 nm_log_dbg (LOGD_IP6, "error processing netlink new/del address message");
478                 return NULL;
479         }
480
481         device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
482         if (!device) {
483                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
484                 return NULL;
485         }
486
487         old_size = nl_cache_nitems (priv->addr_cache);
488         nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL);
489         rtnl_addr_put (rtnladdr);
490
491         /* The kernel will re-notify us of automatically-added addresses
492          * every time it gets another router advertisement. We only want
493          * to notify higher levels if we actually changed something.
494          */
495         if (nl_cache_nitems (priv->addr_cache) == old_size) {
496                 nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message",
497                             device->iface);
498                 return NULL;
499         }
500
501         return device;
502 }
503
504 static NMIP6Device *
505 process_route (NMIP6Manager *manager, struct nl_msg *msg)
506 {
507         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
508         NMIP6Device *device;
509         struct rtnl_route *rtnlroute;
510         int old_size;
511
512         nm_log_dbg (LOGD_IP6, "processing netlink new/del route message");
513
514         rtnlroute = NULL;
515         nl_msg_parse (msg, ref_object, &rtnlroute);
516         if (!rtnlroute) {
517                 nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message");
518                 return NULL;
519         }
520
521         device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
522         if (!device) {
523                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
524                 return NULL;
525         }
526
527         old_size = nl_cache_nitems (priv->route_cache);
528         nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL);
529         rtnl_route_put (rtnlroute);
530
531         /* As above in process_addr */
532         if (nl_cache_nitems (priv->route_cache) == old_size) {
533                 nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message",
534                             device->iface);
535                 return NULL;
536         }
537
538         return device;
539 }
540
541 static NMIP6Device *
542 process_prefix (NMIP6Manager *manager, struct nl_msg *msg)
543 {
544         struct prefixmsg *pmsg;
545         NMIP6Device *device;
546
547         /* We don't care about the prefix itself, but if we receive a
548          * router advertisement telling us to use DHCP, we might not
549          * get any RTM_NEWADDRs or RTM_NEWROUTEs, so this is our only
550          * way to notice immediately that an RA was received.
551          */
552
553         nm_log_dbg (LOGD_IP6, "processing netlink new prefix message");
554
555         pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg));
556         device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex);
557
558         if (!device || device->addrconf_complete) {
559                 nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
560                             device ? device->iface : "(none)");
561                 return NULL;
562         }
563
564         return device;
565 }
566
567 /* RDNSS parsing code based on rdnssd, Copyright 2007 Pierre Ynard,
568  * RĂ©mi Denis-Courmont. GPLv2/3
569  */
570
571 #define ND_OPT_RDNSS 25
572 struct nd_opt_rdnss {
573         uint8_t nd_opt_rdnss_type;
574         uint8_t nd_opt_rdnss_len;
575         uint16_t nd_opt_rdnss_reserved1;
576         uint32_t nd_opt_rdnss_lifetime;
577         /* followed by one or more IPv6 addresses */
578 } __attribute__ ((packed));
579
580 static gboolean
581 process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
582 {
583         size_t opt_len;
584         struct nd_opt_rdnss *rdnss_opt;
585         time_t now = time (NULL);
586         struct in6_addr *addr;
587         GArray *new_servers;
588         NMIP6RDNSS server, *cur_server;
589         gboolean changed = FALSE;
590         guint i;
591
592         opt_len = opt->nd_opt_len;
593
594         if (opt_len < 3 || (opt_len & 1) == 0)
595                 return FALSE;
596
597         rdnss_opt = (struct nd_opt_rdnss *) opt;
598
599         new_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
600
601         /* Pad the DNS server expiry somewhat to give a bit of slack in cases
602          * where one RA gets lost or something (which can happen on unreliable
603          * links like WiFi where certain types of frames are not retransmitted).
604          * Note that 0 has special meaning and is therefore not adjusted.
605          */
606         server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
607         if (server.expires > 0)
608                 server.expires += now + 10;
609
610         for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
611                 char buf[INET6_ADDRSTRLEN + 1];
612
613                 if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
614                         strcpy(buf, "[invalid]");
615
616                 for (i = 0; i < device->rdnss_servers->len; i++) {
617                         cur_server = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
618
619                         if (!IN6_ARE_ADDR_EQUAL (addr, &cur_server->addr))
620                                 continue;
621
622                         cur_server->expires = server.expires;
623
624                         if (server.expires > 0) {
625                                 nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided nameserver %s (expires in %d seconds)",
626                                             device->iface, buf,
627                                             server.expires - now);
628                                 break;
629                         }
630
631                         nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided nameserver %s on router request",
632                                     device->iface, buf);
633
634                         g_array_remove_index (device->rdnss_servers, i);
635                         changed = TRUE;
636                         break;
637                 }
638
639                 if (server.expires == 0)
640                         continue;
641                 if (i < device->rdnss_servers->len)
642                         continue;
643
644                 nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %d seconds)",
645                             device->iface, buf, server.expires - now);
646
647                 server.addr = *addr;
648                 g_array_append_val (new_servers, server);
649         }
650
651         /* New servers must be added in the order they are listed in the
652          * RA option and before any existing servers.
653          *
654          * Note: This is the place to remove servers if we want to cap the
655          *       number of resolvers. The RFC states that the one to expire
656          *       first of the existing servers should be removed.
657          */
658         if (new_servers->len) {
659                 g_array_prepend_vals (device->rdnss_servers,
660                                       new_servers->data, new_servers->len);
661                 changed = TRUE;
662         }
663
664         g_array_free (new_servers, TRUE);
665
666         /* Timeouts may have changed even if IPs didn't */
667         set_rdnss_timeout (device);
668
669         return changed;
670 }
671
672 static NMIP6Device *
673 process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
674 {
675         NMIP6Device *device;
676         struct nduseroptmsg *ndmsg;
677         struct nd_opt_hdr *opt;
678         guint opts_len;
679         gboolean changed = FALSE;
680
681         nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message");
682
683         ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg));
684
685         if (ndmsg->nduseropt_family != AF_INET6 ||
686                 ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
687                 ndmsg->nduseropt_icmp_code != 0) {
688                 nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message");
689                 return NULL;
690         }
691
692         device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex);
693         if (!device) {
694                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
695                 return NULL;
696         }
697
698         opt = (struct nd_opt_hdr *) (ndmsg + 1);
699         opts_len = ndmsg->nduseropt_opts_len;
700
701         while (opts_len >= sizeof (struct nd_opt_hdr)) {
702                 size_t nd_opt_len = opt->nd_opt_len;
703
704                 if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
705                         break;
706
707                 switch (opt->nd_opt_type) {
708                 case ND_OPT_RDNSS:
709                         changed = process_nduseropt_rdnss (device, opt);
710                         break;
711                 }
712
713                 opts_len -= opt->nd_opt_len << 3;
714                 opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3));
715         }
716
717         if (changed)
718                 return device;
719         else
720                 return NULL;
721 }
722
723 static struct nla_policy link_policy[IFLA_MAX + 1] = {
724         [IFLA_PROTINFO] = { .type = NLA_NESTED },
725 };
726
727 static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
728         [IFLA_INET6_FLAGS]      = { .type = NLA_U32 },
729 };
730
731 static NMIP6Device *
732 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
733 {
734         struct nlmsghdr *hdr = nlmsg_hdr (msg);
735         struct ifinfomsg *ifi;
736         NMIP6Device *device;
737         struct nlattr *tb[IFLA_MAX + 1];
738         struct nlattr *pi[IFLA_INET6_MAX + 1];
739         int err;
740
741         ifi = nlmsg_data (hdr);
742         if (ifi->ifi_family != AF_INET6) {
743                 nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family);
744                 return NULL;
745         }
746
747         device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
748         if (!device || device->addrconf_complete) {
749                 nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
750                             device ? device->iface : "(none)");
751                 return NULL;
752         }
753
754         /* FIXME: we have to do this manually for now since libnl doesn't yet
755          * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
756          * we can get rid of this function and just grab IFLA_PROTINFO from
757          * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
758          * the PROTINFO.
759          */
760
761         err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
762         if (err < 0) {
763                 nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO attribute", device->iface);
764                 return NULL;
765         }
766         if (!tb[IFLA_PROTINFO]) {
767                 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface);
768                 return NULL;
769         }
770
771         err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
772         if (err < 0) {
773                 nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface);
774                 return NULL;
775         }
776         if (!pi[IFLA_INET6_FLAGS]) {
777                 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface);
778                 return NULL;
779         }
780
781         device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
782         nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags);
783
784         return device;
785 }
786
787 static void
788 netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
789 {
790         NMIP6Manager *manager = (NMIP6Manager *) user_data;
791         NMIP6Device *device;
792         struct nlmsghdr *hdr;
793         gboolean config_changed = FALSE;
794
795         hdr = nlmsg_hdr (msg);
796         nm_log_dbg (LOGD_HW, "netlink notificate type %d", hdr->nlmsg_type);
797         switch (hdr->nlmsg_type) {
798         case RTM_NEWADDR:
799         case RTM_DELADDR:
800                 device = process_addr (manager, msg);
801                 config_changed = TRUE;
802                 break;
803         case RTM_NEWROUTE:
804         case RTM_DELROUTE:
805                 device = process_route (manager, msg);
806                 config_changed = TRUE;
807                 break;
808         case RTM_NEWPREFIX:
809                 device = process_prefix (manager, msg);
810                 break;
811         case RTM_NEWNDUSEROPT:
812                 device = process_nduseropt (manager, msg);
813                 config_changed = TRUE;
814                 break;
815         case RTM_NEWLINK:
816                 device = process_newlink (manager, msg);
817                 config_changed = TRUE;
818                 break;
819         default:
820                 return;
821         }
822
823         if (device) {
824                 nm_log_dbg (LOGD_IP6, "(%s): syncing device with netlink changes", device->iface);
825                 nm_ip6_device_sync_from_netlink (device, config_changed);
826         }
827 }
828
829 void
830 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
831                                   int ifindex,
832                                   NMSettingIP6Config *s_ip6,
833                                   const char *accept_ra_path)
834 {
835         NMIP6ManagerPrivate *priv;
836         NMIP6Device *device;
837         const char *method = NULL;
838
839         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
840         g_return_if_fail (ifindex > 0);
841
842         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
843
844         device = nm_ip6_device_new (manager, ifindex);
845         g_return_if_fail (device != NULL);
846         g_return_if_fail (   strchr (device->iface, '/') == NULL
847                           && strcmp (device->iface, "all") != 0
848                           && strcmp (device->iface, "default") != 0);
849
850         if (s_ip6)
851                 method = nm_setting_ip6_config_get_method (s_ip6);
852         if (!method)
853                 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
854
855         /* Establish target state and turn router advertisement acceptance on or off */
856         if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
857                 device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
858                 nm_utils_do_sysctl (accept_ra_path, "0\n");
859         } else {
860                 device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
861                 nm_utils_do_sysctl (accept_ra_path, "1\n");
862         }
863 }
864
865 static gboolean
866 poll_ip6_flags (gpointer user_data)
867 {
868         nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL);
869         return TRUE;
870 }
871
872 void
873 nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
874 {
875         NMIP6ManagerPrivate *priv;
876         NMIP6Device *device;
877         CallbackInfo *info;
878
879         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
880         g_return_if_fail (ifindex > 0);
881
882         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
883
884         device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
885         g_return_if_fail (device != NULL);
886
887         nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface);
888
889         device->addrconf_complete = FALSE;
890         device->ra_flags = 0;
891
892         /* Set up a timeout on the transaction to kill it after the timeout */
893         info = callback_info_new (device, 0, FALSE);
894         device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
895                                                                  NM_IP6_TIMEOUT,
896                                                                  finish_addrconf,
897                                                                  info,
898                                                                  (GDestroyNotify) g_free);
899
900         /* Bounce IPv6 on the interface to ensure the kernel will start looking for
901          * new RAs; there doesn't seem to be a better way to do this right now.
902          */
903         if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) {
904                 nm_utils_do_sysctl (device->disable_ip6_path, "1\n");
905                 g_usleep (200);
906                 nm_utils_do_sysctl (device->disable_ip6_path, "0\n");
907         }
908
909         device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor);
910
911         /* Kick off the initial IPv6 flags request */
912         nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
913
914         /* Sync flags, etc, from netlink; this will also notice if the
915          * device is already fully configured and schedule the
916          * ADDRCONF_COMPLETE signal in that case.
917          */
918         nm_ip6_device_sync_from_netlink (device, FALSE);
919 }
920
921 void
922 nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex)
923 {
924         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
925         g_return_if_fail (ifindex > 0);
926
927         g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices,
928                              GINT_TO_POINTER (ifindex));
929 }
930
931 #define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m))
932 #define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m))
933
934 #define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m))
935 #define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m))
936
937 NMIP6Config *
938 nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
939 {
940         NMIP6ManagerPrivate *priv;
941         NMIP6Device *device;
942         NMIP6Config *config;
943         struct rtnl_addr *rtnladdr;
944         struct nl_addr *nladdr;
945         struct in6_addr *addr;
946         NMIP6Address *ip6addr;
947         struct rtnl_route *rtnlroute;
948         struct nl_addr *nldest, *nlgateway;
949         struct in6_addr *dest, *gateway;
950         gboolean defgw_set = FALSE;
951         struct in6_addr defgw;
952         uint32_t metric;
953         NMIP6Route *ip6route;
954         int i;
955
956         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
957         g_return_val_if_fail (ifindex > 0, NULL);
958
959         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
960
961         device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
962                                                       GINT_TO_POINTER (ifindex));
963         if (!device) {
964                 nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
965                 return NULL;
966         }
967
968         config = nm_ip6_config_new ();
969         if (!config) {
970                 nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
971                             device->iface);
972                 return NULL;
973         }
974
975         /* Make sure we refill the route and address caches, otherwise we won't get
976          * up-to-date information here since the netlink route/addr change messages
977          * may be lagging a bit.
978          */
979         nl_cache_refill (priv->nlh, priv->route_cache);
980         nl_cache_refill (priv->nlh, priv->addr_cache);
981
982         /* Add routes */
983         for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
984                 /* Make sure it's an IPv6 route for this device */
985                 if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
986                         continue;
987                 if (rtnl_route_get_family (rtnlroute) != AF_INET6)
988                         continue;
989
990                 nldest = rtnl_route_get_dst (rtnlroute);
991                 if (!nldest || nl_addr_get_family (nldest) != AF_INET6)
992                         continue;
993                 dest = nl_addr_get_binary_addr (nldest);
994
995                 nlgateway = rtnl_route_get_gateway (rtnlroute);
996                 if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6)
997                         continue;
998                 gateway = nl_addr_get_binary_addr (nlgateway);
999
1000                 if (rtnl_route_get_dst_len (rtnlroute) == 0) {
1001                         /* Default gateway route; don't add to normal routes but to each address */
1002                         if (!defgw_set) {
1003                                 memcpy (&defgw, gateway, sizeof (defgw));
1004                                 defgw_set = TRUE;
1005                         }
1006                         continue;
1007                 }
1008
1009                 /* Also ignore link-local routes where the destination and gateway are
1010                  * the same, which apparently get added by the kernel but return -EINVAL
1011                  * when we try to add them via netlink.
1012                  */
1013                 if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway))
1014                         continue;
1015
1016                 ip6route = nm_ip6_route_new ();
1017                 nm_ip6_route_set_dest (ip6route, dest);
1018                 nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
1019                 nm_ip6_route_set_next_hop (ip6route, gateway);
1020                 metric = rtnl_route_get_metric (rtnlroute, 1);
1021                 if (metric != UINT_MAX)
1022                         nm_ip6_route_set_metric (ip6route, metric);
1023                 nm_ip6_config_take_route (config, ip6route);
1024         }
1025
1026         /* Add addresses */
1027         for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
1028                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
1029                         continue;
1030
1031                 nladdr = rtnl_addr_get_local (rtnladdr);
1032                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
1033                         continue;
1034
1035                 addr = nl_addr_get_binary_addr (nladdr);
1036                 ip6addr = nm_ip6_address_new ();
1037                 nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
1038                 nm_ip6_address_set_address (ip6addr, addr);
1039                 nm_ip6_config_take_address (config, ip6addr);
1040                 if (defgw_set)
1041                         nm_ip6_address_set_gateway (ip6addr, &defgw);
1042         }
1043
1044         /* Add DNS servers */
1045         if (device->rdnss_servers) {
1046                 NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);
1047
1048                 for (i = 0; i < device->rdnss_servers->len; i++)
1049                         nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
1050         }
1051
1052         return config;
1053 }
1054
1055 /******************************************************************/
1056
1057 static NMIP6Manager *
1058 nm_ip6_manager_new (void)
1059 {
1060         NMIP6Manager *manager;
1061         NMIP6ManagerPrivate *priv;
1062
1063         manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
1064         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1065
1066         if (!priv->devices) {
1067                 nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
1068                 g_object_unref (manager);
1069                 manager = NULL;
1070         }
1071
1072         return manager;
1073 }
1074
1075 static NMIP6Manager *singleton = NULL;
1076
1077 NMIP6Manager *
1078 nm_ip6_manager_get (void)
1079 {
1080         if (!singleton) {
1081                 singleton = nm_ip6_manager_new ();
1082                 g_assert (singleton);
1083         } else
1084                 g_object_ref (singleton);
1085
1086         return singleton;
1087 }
1088
1089 static void
1090 nm_ip6_manager_init (NMIP6Manager *manager)
1091 {
1092         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1093
1094         priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1095                                                NULL,
1096                                                (GDestroyNotify) nm_ip6_device_destroy);
1097
1098         priv->monitor = nm_netlink_monitor_get ();
1099         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
1100         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
1101         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
1102         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
1103
1104         priv->netlink_id = g_signal_connect (priv->monitor, "notification",
1105                                              G_CALLBACK (netlink_notification), manager);
1106
1107         priv->nlh = nm_netlink_get_default_handle ();
1108         priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
1109         priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
1110 }
1111
1112 static void
1113 finalize (GObject *object)
1114 {
1115         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
1116
1117         g_signal_handler_disconnect (priv->monitor, priv->netlink_id);
1118
1119         g_hash_table_destroy (priv->devices);
1120         g_object_unref (priv->monitor);
1121         nl_cache_free (priv->addr_cache);
1122         nl_cache_free (priv->route_cache);
1123
1124         singleton = NULL;
1125
1126         G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
1127 }
1128
1129 static void
1130 nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
1131 {
1132         GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
1133
1134         g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
1135
1136         /* virtual methods */
1137         object_class->finalize = finalize;
1138
1139         /* signals */
1140         signals[ADDRCONF_COMPLETE] =
1141                 g_signal_new ("addrconf-complete",
1142                                           G_OBJECT_CLASS_TYPE (object_class),
1143                                           G_SIGNAL_RUN_FIRST,
1144                                           G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
1145                                           NULL, NULL,
1146                                           _nm_marshal_VOID__INT_UINT_BOOLEAN,
1147                                           G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
1148
1149         signals[CONFIG_CHANGED] =
1150                 g_signal_new ("config-changed",
1151                                           G_OBJECT_CLASS_TYPE (object_class),
1152                                           G_SIGNAL_RUN_FIRST,
1153                                           G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
1154                                           NULL, NULL,
1155                                           _nm_marshal_VOID__INT_UINT_BOOLEAN,
1156                                           G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
1157 }
1158