Example #1
0
static int
__ni_rtevent_process_rdnss_info(ni_netdev_t *dev, const struct nd_opt_hdr *opt,
				size_t len)
{
	const struct ni_nd_opt_rdnss_info_p *ropt;
	char buf[INET6_ADDRSTRLEN+1] = {'\0'};
	const struct in6_addr* addr;
	ni_ipv6_devinfo_t *ipv6;
	unsigned int lifetime;
	struct timeval acquired;
	ni_bool_t emit = FALSE;
	const char *server;

	if (opt == NULL || len < (sizeof(*ropt) + sizeof(*addr))) {
		ni_error("%s: unable to parse ipv6 rdnss info event data -- too short",
				dev->name);
		return -1;
	}

	ipv6 = ni_netdev_get_ipv6(dev);
	if (!ipv6) {
		ni_error("%s: unable to allocate device ipv6 structure: %m",
				dev->name);
		return -1;
	}

	ropt = (const struct ni_nd_opt_rdnss_info_p *)opt;

	ni_timer_get_time(&acquired);
	lifetime = ntohl(ropt->nd_opt_rdnss_lifetime);
	len -= sizeof(*ropt);
	addr = &ropt->nd_opt_rdnss_addr[0];
	for ( ; len >= sizeof(*addr); len -= sizeof(*addr), ++addr) {
		if (IN6_IS_ADDR_LOOPBACK(addr) || IN6_IS_ADDR_UNSPECIFIED(addr)) {
			server = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
			ni_debug_verbose(NI_LOG_DEBUG2, NI_TRACE_IPV6|NI_TRACE_EVENTS,
					"%s: ignoring invalid rdnss server address %s",
					dev->name, server);
			continue;
		}

		if (!ni_ipv6_ra_rdnss_list_update(&ipv6->radv.rdnss, addr,
					lifetime, &acquired)) {
			server = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
			ni_debug_verbose(NI_LOG_DEBUG, NI_TRACE_IPV6|NI_TRACE_EVENTS,
					"%s: failed to track ipv6 rnssl server %s",
					dev->name, server);
			continue;
		}

		emit = TRUE;
	}

	if (emit)
		__ni_netdev_nduseropt_event(dev, NI_EVENT_RDNSS_UPDATE);
	return 0;
}
Example #2
0
File: ipv6.c Project: mijos/wicked
void
ni_netdev_set_ipv6(ni_netdev_t *dev, ni_ipv6_devconf_t *conf)
{
	if (conf != NULL) {
		ni_netdev_get_ipv6(dev);
		dev->ipv6->conf = *conf;
	} else if (dev->ipv6) {
		ni_ipv6_devinfo_free(dev->ipv6);
		dev->ipv6 = NULL;
	}
}
Example #3
0
File: ipv6.c Project: mijos/wicked
int
ni_system_ipv6_devinfo_set(ni_netdev_t *dev, const ni_ipv6_devconf_t *conf)
{
	ni_ipv6_devinfo_t *ipv6;

	if (!conf || !(ipv6 = ni_netdev_get_ipv6(dev)))
		return -1;

	if (!ni_ipv6_supported()) {
		ipv6->conf.enabled = NI_TRISTATE_DISABLE;
		if (ni_tristate_is_enabled(conf->enabled)) {
			errno = EAFNOSUPPORT;
			return -1;
		}
		return 0;
	}

	if (ni_tristate_is_set(conf->enabled)) {
		if (__ni_system_ipv6_devinfo_change_int(dev->name, "disable_ipv6",
				ni_tristate_is_enabled(conf->enabled) ? 0 : 1) < 0)
			return -1;

		ni_tristate_set(&ipv6->conf.enabled, conf->enabled);
	}

	/* If we're disabling IPv6 on this interface, we're done! */
	if (ni_tristate_is_disabled(conf->enabled)) {
		__ni_ipv6_ra_info_reset(&dev->ipv6->radv);
		return 0;
	}

	if (__ni_system_ipv6_devinfo_change_int(dev->name, "autoconf",
						conf->autoconf) == 0)
		ipv6->conf.autoconf = conf->autoconf;

	if (__ni_system_ipv6_devinfo_change_int(dev->name, "forwarding",
						conf->forwarding) == 0)
		ipv6->conf.forwarding = conf->forwarding;

	if (__ni_system_ipv6_devinfo_change_int(dev->name, "accept_redirects",
						conf->accept_redirects) == 0)
		ipv6->conf.accept_redirects = conf->accept_redirects;

	if (ipv6->conf.privacy != NI_TRISTATE_DEFAULT) {
		/* kernel is using -1 for loopback, ptp, ... */
		if (__ni_system_ipv6_devinfo_change_int(dev->name,
			"use_tempaddr",	conf->privacy) == 0) {
			ipv6->conf.privacy = conf->privacy;
		}
	}

	return 0;
}
Example #4
0
File: ipv6.c Project: mijos/wicked
/*
 * Discover current IPv6 device settings
 */
int
ni_system_ipv6_devinfo_get(ni_netdev_t *dev, ni_ipv6_devinfo_t *ipv6)
{
	if (ipv6 == NULL)
		ipv6 = ni_netdev_get_ipv6(dev);

	if (!ni_ipv6_supported()) {
		__ni_ipv6_devconf_reset(&ipv6->conf);
		__ni_ipv6_ra_info_reset(&ipv6->radv);
		ipv6->conf.enabled = NI_TRISTATE_DISABLE;
		return 0;
	}

	/*
	 * dhcpcd does something very odd when shutting down an interface;
	 * in addition to removing all IPv4 addresses, it also removes any
	 * IPv6 addresses. The kernel seems to take this as "disable IPv6
	 * on this interface", and subsequently, /proc/sys/ipv6/conf/<ifname>
	 * is gone.
	 * When we bring the interface back up, everything is fine; but until
	 * then we need to ignore this glitch.
	 */
	if (ni_sysctl_ipv6_ifconfig_is_present(dev->name)) {
		int val;

		if (ni_sysctl_ipv6_ifconfig_get_int(dev->name, "disable_ipv6", &val) >= 0)
			ni_tristate_set(&ipv6->conf.enabled, !val);

		if (ni_sysctl_ipv6_ifconfig_get_int(dev->name, "forwarding", &val) >= 0)
			ni_tristate_set(&ipv6->conf.forwarding, !!val);

		if (ni_sysctl_ipv6_ifconfig_get_int(dev->name, "autoconf", &val) >= 0)
			ni_tristate_set(&ipv6->conf.autoconf, !!val);

		if (ni_sysctl_ipv6_ifconfig_get_int(dev->name, "accept_redirects", &val) >= 0)
			ni_tristate_set(&ipv6->conf.accept_redirects, !!val);

		if (ni_sysctl_ipv6_ifconfig_get_int(dev->name, "use_tempaddr", &val) >= 0)
			ipv6->conf.privacy = val < -1 ? -1 : (val > 2 ? 2 : val);
	} else {
		ni_warn("%s: cannot get ipv6 device attributes", dev->name);

		/* Reset to defaults */
		__ni_ipv6_devconf_reset(&ipv6->conf);
		__ni_ipv6_ra_info_reset(&ipv6->radv);
	}

	return 0;
}
Example #5
0
static int
__ni_rtevent_process_dnssl_info(ni_netdev_t *dev, const struct nd_opt_hdr *opt, size_t len)
{
	const struct ni_nd_opt_dnssl_info_p *dopt;
	ni_ipv6_devinfo_t *ipv6;
	unsigned int lifetime;
	struct timeval acquired;
	size_t length, cnt, off;
	ni_bool_t emit = FALSE;
	char domain[256];

	if (opt == NULL || len < sizeof(*dopt)) {
		ni_error("%s: unable to parse ipv6 dnssl info event data -- too short",
				dev->name);
		return -1;
	}

	ipv6 = ni_netdev_get_ipv6(dev);
	if (!ipv6) {
		ni_error("%s: unable to allocate device ipv6 structure: %m",
				dev->name);
		return -1;
	}

	dopt = (const struct ni_nd_opt_dnssl_info_p *)opt;
	len -= sizeof(*dopt);

	ni_timer_get_time(&acquired);
	lifetime = ntohl(dopt->nd_opt_dnssl_lifetime);

	length = 0;
	domain[length] = '\0';
	for (off = 0; off < len ; ) {
		cnt = dopt->nd_opt_dnssl_list[off++];
		if (cnt == 0) {
			/* just padding */
			if (domain[0] == '\0')
				continue;

			domain[length] = '\0';
			if (!ni_check_domain_name(domain, length, 0)) {
				ni_debug_verbose(NI_LOG_DEBUG, NI_TRACE_IPV6|NI_TRACE_EVENTS,
					"%s: ignoring suspect DNSSL domain: %s",
					dev->name, ni_print_suspect(domain, length));
			} else
			if (!ni_ipv6_ra_dnssl_list_update(&ipv6->radv.dnssl,
						domain, lifetime, &acquired)) {
				ni_debug_verbose(NI_LOG_DEBUG, NI_TRACE_IPV6|NI_TRACE_EVENTS,
						"%s: unable to track ipv6 dnssl domain %s",
						dev->name, domain);
			} else
				emit = TRUE;

			length = 0;
			domain[length] = '\0';
			continue;
		}

		if ((off + cnt >= len) || (length + cnt + 2 > sizeof(domain)))
			break;

		if (length)
			domain[length++] = '.';
		memcpy(&domain[length], &dopt->nd_opt_dnssl_list[off], cnt);
		off += cnt;
		length += cnt;
		domain[length] = '\0';
	}

	if (emit)
		__ni_netdev_nduseropt_event(dev, NI_EVENT_DNSSL_UPDATE);
	return 0;
}
Example #6
0
/*
 * Process NEWPREFIX event. This essentially maps 1:1 to IPv6 router advertisements received
 * by the kernel.
 */
int
__ni_rtevent_newprefix(ni_netconfig_t *nc, const struct sockaddr_nl *nladdr, struct nlmsghdr *h)
{
	struct prefixmsg *pfx;
	ni_ipv6_devinfo_t *ipv6;
	ni_ipv6_ra_pinfo_t *pi, *old = NULL;
	ni_netdev_t *dev;

	if (!(pfx = ni_rtnl_prefixmsg(h, RTM_NEWPREFIX)))
		return -1;

	dev = ni_netdev_by_index(nc, pfx->prefix_ifindex);
	if (!dev) {
		ni_debug_events("ipv6 prefix info event for unknown device index: %u",
				pfx->prefix_ifindex);
		return 0;
	}

	ipv6 = ni_netdev_get_ipv6(dev);
	if (!ipv6) {
		ni_error("%s: unable to allocate device ipv6 structure: %m",
				dev->name);
		return -1;
	}

	pi = calloc(1, sizeof(*pi));
	if (!pi) {
		ni_error("%s: unable to allocate ipv6 prefix info structure: %m",
				dev->name);
		return -1;
	}

	ni_timer_get_time(&pi->acquired);

	if (__ni_rtnl_parse_newprefix(dev->name, h, pfx, pi) < 0) {
		ni_error("%s: unable to parse ipv6 prefix info event data",
				dev->name);
		ni_ipv6_ra_pinfo_free(pi);
		return -1;
	}

	if ((old = ni_ipv6_ra_pinfo_list_remove(&ipv6->radv.pinfo, pi)) != NULL) {
		if (pi->valid_lft != NI_LIFETIME_EXPIRED) {
			/* Replace with updated prefix info - most recent in front */
			ni_ipv6_ra_pinfo_list_prepend(&ipv6->radv.pinfo, pi);
			__ni_netdev_prefix_event(dev, NI_EVENT_PREFIX_UPDATE, pi);
		} else {
			/* A lifetime of 0 means the router requests a prefix remove;
			 * at least 3.0.x kernel set valid lft to 0 and keep pref. */
			ni_ipv6_ra_pinfo_free(pi);
			__ni_netdev_prefix_event(dev, NI_EVENT_PREFIX_DELETE, old);
		}
		free(old);
	} else if (pi->valid_lft != NI_LIFETIME_EXPIRED) {
		/* Add prefix info - most recent in front */
		ni_ipv6_ra_pinfo_list_prepend(&ipv6->radv.pinfo, pi);
		__ni_netdev_prefix_event(dev, NI_EVENT_PREFIX_UPDATE, pi);
	} else {
		/* Request to remove unhandled prefix (missed event?), ignore it. */
		ni_ipv6_ra_pinfo_free(pi);
	}

	return 0;
}