ip6: pad RDNSS and DNSSL lifetimes to a minimum lifetime value (rh #60055)
[NetworkManager.git] / src / ip6-manager / nm-ip6-manager.c
index 4e4a2ef..8f05ddc 100644 (file)
@@ -213,6 +213,44 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
        return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
 }
 
+static char *
+device_get_iface (NMIP6Device *device)
+{
+       return device ? device->iface : "unknown";
+}
+
+static const char *
+state_to_string (NMIP6DeviceState state)
+{
+       switch (state) {
+       case NM_IP6_DEVICE_UNCONFIGURED:
+               return "unconfigured";
+       case NM_IP6_DEVICE_GOT_LINK_LOCAL:
+               return "got-link-local";
+       case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
+               return "got-ra";
+       case NM_IP6_DEVICE_GOT_ADDRESS:
+               return "got-address";
+       case NM_IP6_DEVICE_TIMED_OUT:
+               return "timed-out";
+       default:
+               return "unknown";
+       }
+}
+
+static void
+device_set_state (NMIP6Device *device, NMIP6DeviceState state)
+{
+       NMIP6DeviceState oldstate;
+
+       g_return_if_fail (device != NULL);
+
+       oldstate = device->state;
+       device->state = state;
+       nm_log_dbg (LOGD_IP6, "(%s) IP6 device state: %s -> %s",
+                   device_get_iface (device), state_to_string (oldstate), state_to_string (state));
+}
+
 /******************************************************************/
 
 typedef struct {
@@ -398,25 +436,6 @@ callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
        return info;
 }
 
-static const char *
-state_to_string (NMIP6DeviceState state)
-{
-       switch (state) {
-       case NM_IP6_DEVICE_UNCONFIGURED:
-               return "unconfigured";
-       case NM_IP6_DEVICE_GOT_LINK_LOCAL:
-               return "got-link-local";
-       case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
-               return "got-ra";
-       case NM_IP6_DEVICE_GOT_ADDRESS:
-               return "got-address";
-       case NM_IP6_DEVICE_TIMED_OUT:
-               return "timed-out";
-       default:
-               return "unknown";
-       }
-}
-
 static void
 check_addresses (NMIP6Device *device)
 {
@@ -453,11 +472,11 @@ check_addresses (NMIP6Device *device)
 
                if (IN6_IS_ADDR_LINKLOCAL (addr)) {
                        if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
-                               device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
+                               device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL);
                        device->has_linklocal = TRUE;
                } else {
                        if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
-                               device->state = NM_IP6_DEVICE_GOT_ADDRESS;
+                               device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS);
                        device->has_nonlinklocal = TRUE;
                }
        }
@@ -467,7 +486,7 @@ check_addresses (NMIP6Device *device)
         * regress from GOT_LINK_LOCAL back to UNCONFIGURED.
         */
        if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal)
-               device->state = NM_IP6_DEVICE_UNCONFIGURED;
+               device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED);
 
        nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)",
                    device->iface, state_to_string (device->state));
@@ -483,7 +502,7 @@ check_ra_flags (NMIP6Device *device)
            && (device->ra_flags & IF_RA_RCVD)) {
 
                if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
-                       device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
+                       device_set_state (device, NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT);
 
                if (device->ra_flags & IF_RA_MANAGED) {
                        device->dhcp_opts = IP6_DHCP_OPT_MANAGED;
@@ -574,16 +593,51 @@ ref_object (struct nl_object *obj, void *data)
        *out = obj;
 }
 
+static void
+dump_address_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_addr *rtnladdr)
+{
+       char *event;
+       struct nl_addr *addr;
+       char addr_str[40] = "none";
+
+       event = hdr->nlmsg_type == RTM_NEWADDR ? "new" : "lost";
+       addr = rtnl_addr_get_local (rtnladdr);
+       if (addr)
+               nl_addr2str (addr, addr_str, 40);
+
+       nm_log_dbg (LOGD_IP6, "(%s) %s address: %s", device_get_iface (device), event, addr_str);
+}
+
+static void
+dump_route_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_route *rtnlroute)
+{
+       char *event;
+       struct nl_addr *dst;
+       char dst_str[40] = "none";
+       struct nl_addr *gateway;
+       char gateway_str[40] = "none";
+
+       event = hdr->nlmsg_type == RTM_NEWROUTE ? "new" : "lost";
+       dst = rtnl_route_get_dst (rtnlroute);
+       gateway = rtnl_route_get_gateway (rtnlroute);
+       if (dst)
+               nl_addr2str (dst, dst_str, 40);
+       if (gateway)
+               nl_addr2str (gateway, gateway_str, 40);
+
+       nm_log_dbg (LOGD_IP6, "(%s) %s route: %s via %s",device_get_iface (device), event, dst_str, gateway_str);
+}
+
 static NMIP6Device *
-process_addr (NMIP6Manager *manager, struct nl_msg *msg)
+process_address_change (NMIP6Manager *manager, struct nl_msg *msg)
 {
        NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
        NMIP6Device *device;
+       struct nlmsghdr *hdr;
        struct rtnl_addr *rtnladdr;
        int old_size;
 
-       nm_log_dbg (LOGD_IP6, "processing netlink new/del address message");
-
+       hdr = nlmsg_hdr (msg);
        rtnladdr = NULL;
        nl_msg_parse (msg, ref_object, &rtnladdr);
        if (!rtnladdr) {
@@ -592,39 +646,34 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg)
        }
 
        device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
-       if (!device) {
-               nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
-               rtnl_addr_put (rtnladdr);
-               return NULL;
-       }
 
        old_size = nl_cache_nitems (priv->addr_cache);
        nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL);
-       rtnl_addr_put (rtnladdr);
 
        /* The kernel will re-notify us of automatically-added addresses
         * every time it gets another router advertisement. We only want
         * to notify higher levels if we actually changed something.
         */
-       if (nl_cache_nitems (priv->addr_cache) == old_size) {
-               nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message",
-                           device->iface);
+       nm_log_dbg (LOGD_IP6, "(%s): address cache size: %d -> %d:",
+                   device_get_iface (device), old_size, nl_cache_nitems (priv->addr_cache));
+       dump_address_change (device, hdr, rtnladdr);
+       rtnl_addr_put (rtnladdr);
+       if (nl_cache_nitems (priv->addr_cache) == old_size)
                return NULL;
-       }
 
        return device;
 }
 
 static NMIP6Device *
-process_route (NMIP6Manager *manager, struct nl_msg *msg)
+process_route_change (NMIP6Manager *manager, struct nl_msg *msg)
 {
        NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
        NMIP6Device *device;
+       struct nlmsghdr *hdr;
        struct rtnl_route *rtnlroute;
        int old_size;
 
-       nm_log_dbg (LOGD_IP6, "processing netlink new/del route message");
-
+       hdr = nlmsg_hdr (msg);
        rtnlroute = NULL;
        nl_msg_parse (msg, ref_object, &rtnlroute);
        if (!rtnlroute) {
@@ -633,22 +682,17 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg)
        }
 
        device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
-       if (!device) {
-               nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
-               rtnl_route_put (rtnlroute);
-               return NULL;
-       }
 
        old_size = nl_cache_nitems (priv->route_cache);
        nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
-       rtnl_route_put (rtnlroute);
 
-       /* As above in process_addr */
-       if (nl_cache_nitems (priv->route_cache) == old_size) {
-               nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message",
-                           device->iface);
+       /* As above in process_address_change */
+       nm_log_dbg (LOGD_IP6, "(%s): route cache size: %d -> %d:",
+                   device_get_iface (device), old_size, nl_cache_nitems (priv->route_cache));
+       dump_route_change (device, hdr, rtnlroute);
+       rtnl_route_put (rtnlroute);
+       if (nl_cache_nitems (priv->route_cache) == old_size)
                return NULL;
-       }
 
        return device;
 }
@@ -704,7 +748,9 @@ process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
         */
        server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
        if (server.expires > 0)
-               server.expires += now + 10;
+               if (server.expires < 7200)
+                       server.expires = 7200;
+               server.expires += now;
 
        for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
                char buf[INET6_ADDRSTRLEN + 1];
@@ -835,7 +881,9 @@ process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
         */
        domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
        if (domain.expires > 0)
-               domain.expires += now + 10;
+               if (domain.expires < 7200)
+                       domain.expires = 7200;
+               domain.expires += now;
 
        while (opt_len) {
                const char *domain_str;
@@ -1081,11 +1129,11 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
        switch (hdr->nlmsg_type) {
        case RTM_NEWADDR:
        case RTM_DELADDR:
-               device = process_addr (manager, msg);
+               device = process_address_change (manager, msg);
                break;
        case RTM_NEWROUTE:
        case RTM_DELROUTE:
-               device = process_route (manager, msg);
+               device = process_route_change (manager, msg);
                break;
        case RTM_NEWNDUSEROPT:
                device = process_nduseropt (manager, msg);
@@ -1226,8 +1274,6 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
        struct rtnl_route *rtnlroute;
        struct nl_addr *nldest, *nlgateway;
        struct in6_addr *dest, *gateway;
-       gboolean defgw_set = FALSE;
-       struct in6_addr defgw;
        uint32_t metric;
        NMIP6Route *ip6route;
        int i;
@@ -1278,9 +1324,8 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 
                if (rtnl_route_get_dst_len (rtnlroute) == 0) {
                        /* Default gateway route; don't add to normal routes but to each address */
-                       if (!defgw_set) {
-                               memcpy (&defgw, gateway, sizeof (defgw));
-                               defgw_set = TRUE;
+                       if (!nm_ip6_config_get_gateway (config)) {
+                               nm_ip6_config_set_gateway (config, gateway);
                        }
                        continue;
                }
@@ -1316,8 +1361,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
                nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
                nm_ip6_address_set_address (ip6addr, addr);
                nm_ip6_config_take_address (config, ip6addr);
-               if (defgw_set)
-                       nm_ip6_address_set_gateway (ip6addr, &defgw);
+               gateway = nm_ip6_config_get_gateway (config);
+               if (gateway)
+                       nm_ip6_address_set_gateway (ip6addr, gateway);
        }
 
        /* Add DNS servers */