static gboolean dnssl_expired (gpointer user_data) { NMIP6Device *device = user_data; CallbackInfo info = { device, IP6_DHCP_OPT_NONE }; nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface); set_dnssl_timeout (device); emit_config_changed (&info); return FALSE; }
static gboolean dnssl_needs_refresh (gpointer user_data) { NMIP6Device *device = user_data; gchar *msg; msg = g_strdup_printf ("IPv6 DNSSL due to expire in %d seconds", device->dnssl_timeout); device_send_router_solicitation (device, msg); g_free (msg); set_dnssl_timeout (device); return FALSE; }
static gboolean process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt) { size_t opt_len; struct nd_opt_dnssl *dnssl_opt; unsigned char *opt_ptr; time_t now = time (NULL); GArray *new_domains; NMIP6DNSSL domain, *cur_domain; gboolean changed; guint i; opt_len = opt->nd_opt_len; if (opt_len < 2) return FALSE; dnssl_opt = (struct nd_opt_dnssl *) opt; opt_ptr = (unsigned char *)(dnssl_opt + 1); opt_len = (opt_len - 1) * 8; /* prefer bytes for later handling */ new_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL)); changed = FALSE; /* Pad the DNS server expiry somewhat to give a bit of slack in cases * where one RA gets lost or something (which can happen on unreliable * links like wifi where certain types of frames are not retransmitted). * Note that 0 has special meaning and is therefore not adjusted. */ domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime); if (domain.expires > 0) domain.expires += now + 10; while (opt_len) { const char *domain_str; domain_str = parse_dnssl_domain (opt_ptr, opt_len); if (domain_str == NULL) { nm_log_dbg (LOGD_IP6, "(%s): invalid DNSSL option, parsing aborted", device->iface); break; } /* The DNSSL encoding of domains happen to occupy the same size * as the length of the resulting string, including terminating * null. */ opt_ptr += strlen (domain_str) + 1; opt_len -= strlen (domain_str) + 1; /* Ignore empty domains. They're probably just padding... */ if (domain_str[0] == '\0') continue; /* Update cached domain information if we've seen this domain before */ for (i = 0; i < device->dnssl_domains->len; i++) { cur_domain = &(g_array_index (device->dnssl_domains, NMIP6DNSSL, i)); if (strcmp (domain_str, cur_domain->domain) != 0) continue; cur_domain->expires = domain.expires; if (domain.expires > 0) { nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided domain %s (expires in %ld seconds)", device->iface, domain_str, domain.expires - now); break; } nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided domain %s on router request", device->iface, domain_str); g_array_remove_index (device->dnssl_domains, i); changed = TRUE; break; } if (domain.expires == 0) continue; if (i < device->dnssl_domains->len) continue; nm_log_dbg (LOGD_IP6, "(%s): found RA-provided domain %s (expires in %ld seconds)", device->iface, domain_str, domain.expires - now); g_assert (strlen (domain_str) < sizeof (domain.domain)); strcpy (domain.domain, domain_str); g_array_append_val (new_domains, domain); } /* New domains must be added in the order they are listed in the * RA option and before any existing domains. * * Note: This is the place to remove domains if we want to cap the * number of domains. The RFC states that the one to expire * first of the existing domains should be removed. */ if (new_domains->len) { g_array_prepend_vals (device->dnssl_domains, new_domains->data, new_domains->len); changed = TRUE; } g_array_free (new_domains, TRUE); /* Timeouts may have changed even if domains didn't */ set_dnssl_timeout (device); return changed; }