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