Example #1
0
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;
}
Example #3
0
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;
}