Beispiel #1
0
static ni_bool_t
ni_ifup_start_policies(ni_ifworker_array_t *array, ni_bool_t set_persistent)
{
	unsigned int i;
	ni_bool_t rv = TRUE;

	for (i = 0; i < array->count; i++) {
		ni_ifworker_t *w = array->data[i];

		if (set_persistent)
			ni_client_state_set_persistent(w->config.node);

		if (!ni_ifup_hire_nanny(w)) {
			ni_error("%s: unable to apply configuration to nanny", w->name);
			rv = FALSE;
		}
		else
			ni_info("%s: configuration applied to nanny", w->name);
	}

	if (0 == array->count)
		printf("ifup: no matching interfaces\n");

	return rv;
}
Beispiel #2
0
static int
ni_dhcp4_process_offer(ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease)
{
	char abuf1[INET_ADDRSTRLEN];
	char abuf2[INET_ADDRSTRLEN];

	/* TBD: We should be smarter here.
	 *
	 *  -	track "bad" leases, and blacklist them for a while.
	 *	(eg addresses that fail the ARP check).
	 *
	 *  -	try to detect if we woke up in a different network
	 *	environment; in that case there's no point in attempting
	 *	to renew the same old lease forever. Some MS based DHCP
	 *	servers in airports and hotels never seem to send NAKs
	 *	in such as case.
	 */

	inet_ntop(AF_INET, &lease->dhcp4.address, abuf1, sizeof(abuf1));
	inet_ntop(AF_INET, &lease->dhcp4.server_id, abuf2, sizeof(abuf2));

	ni_info("%s: Received offer for %s from %s", dev->ifname, abuf1, abuf2);
	if (dev->config->dry_run == NI_DHCP4_RUN_OFFER) {
		ni_dhcp4_send_event(NI_DHCP4_EVENT_ACQUIRED, dev, lease);
		ni_dhcp4_fsm_restart(dev);
		ni_dhcp4_device_stop(dev);
	} else {
		ni_dhcp4_fsm_request(dev, lease);
	}
	return 0;
}
Beispiel #3
0
int
ni_ethtool_set_priv_flags(const char *ifname, ni_ethtool_t *ethtool, const ni_ethtool_priv_flags_t *pflags)
{
	static const ni_ethtool_cmd_info_t NI_ETHTOOL_CMD_SPFLAGS = {
		ETHTOOL_SPFLAGS,	"set priv-flags"
	};
	struct ethtool_value ecmd;
	unsigned int i, bit;
	const char *name;
	ni_bool_t enabled;
	int ret;

	if (!pflags || !pflags->names.count)
		return 1; /* nothing to set */
	if (!ethtool->priv_flags && (ret = ni_ethtool_get_priv_flags(ifname, ethtool)) < 0)
		return ret;
	if (!ethtool->priv_flags || !ethtool->priv_flags->names.count)
		return -EOPNOTSUPP;

	memset(&ecmd, 0, sizeof(ecmd));
	ecmd.data = ethtool->priv_flags->bitmap;
	/* set every single bit separately in case one fails? */
	for (i = 0; i < pflags->names.count; ++i) {
		name = pflags->names.data[i];
		if (ni_string_empty(name))
			continue;

		enabled = !!(pflags->bitmap & NI_BIT(i));
		bit = ni_string_array_index(&ethtool->priv_flags->names, name);
		if (bit == -1U) {
			ni_info("%s: unable to set unknown driver private flag '%s'",
					ifname, name);
			continue;
		}

		ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_IFCONFIG,
				"%s: setting driver private flag '%s' to %s",
				ifname, name, ni_format_boolean(enabled));
		if (enabled)
			ecmd.data |= NI_BIT(bit);
		else
			ecmd.data &= ~NI_BIT(bit);
	}
	if (ecmd.data == ethtool->priv_flags->bitmap)
		return 0;

	ret = ni_ethtool_call(ifname, &NI_ETHTOOL_CMD_SPFLAGS, &ecmd, NULL);
	ni_ethtool_set_supported(ethtool, NI_ETHTOOL_SUPP_SET_PRIV_FLAGS,
				ret != -EOPNOTSUPP);
	if (ret < 0)
		return ret;

	return 0;
}
Beispiel #4
0
int
ni_dhcp4_fsm_renewal(ni_dhcp4_device_t *dev)
{
	int rv;

	ni_info("%s: Initiating renewal of DHCPv4 lease",
		dev->ifname);

	dev->fsm.state = NI_DHCP4_STATE_RENEWING;
	rv = ni_dhcp4_device_send_message_unicast(dev, DHCP4_REQUEST, dev->lease);

	ni_dhcp4_fsm_set_deadline(dev,
			dev->lease->time_acquired + dev->lease->dhcp4.rebind_time);
	return rv;
}
Beispiel #5
0
int
ni_dhcp4_fsm_rebind(ni_dhcp4_device_t *dev)
{
	int rv;

	ni_info("%s: Initiating rebind of DHCPv4 lease",
		dev->ifname);

	dev->lease->dhcp4.server_id.s_addr = 0;

	dev->fsm.state = NI_DHCP4_STATE_REBINDING;
	rv = ni_dhcp4_device_send_message(dev, DHCP4_REQUEST, dev->lease);

	ni_dhcp4_fsm_set_deadline(dev,
			dev->lease->time_acquired + dev->lease->dhcp4.lease_time);
	return rv;
}
Beispiel #6
0
int
ni_dhcp4_fsm_request(ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease)
{
	int rv;

	ni_info("%s: Requesting DHCPv4 lease with timeout %d sec",
		dev->ifname, dev->config->request_timeout);

	dev->fsm.state = NI_DHCP4_STATE_REQUESTING;
	rv = ni_dhcp4_device_send_message(dev, DHCP4_REQUEST, lease);

	/* Ignore the return value; sending the request may actually
	 * fail transiently */
	ni_dhcp4_fsm_set_timeout(dev, dev->config->request_timeout);

	return rv;
}
Beispiel #7
0
int
ni_dhcp4_fsm_arp_validate(ni_dhcp4_device_t *dev)
{
	struct in_addr null = { 0 };
	struct in_addr claim;

	if (!dev || !dev->lease)
		return -1;

	claim = dev->lease->dhcp4.address;
	if (dev->arp.handle == NULL) {
		dev->arp.handle = ni_arp_socket_open(&dev->system,
				ni_dhcp4_fsm_process_arp_packet, dev);
		if (!dev->arp.handle->user_data) {
			ni_error("%s: unable to create ARP handle", dev->ifname);
			return -1;
		}
	}

	if (dev->arp.nprobes) {
		ni_debug_dhcp("%s: arp validate: probing for %s",
				dev->ifname, inet_ntoa(claim));
		ni_arp_send_request(dev->arp.handle, null, claim);
		dev->arp.nprobes--;
	} else if (dev->arp.nclaims) {
		ni_debug_dhcp("%s: arp validate: claiming %s",
				dev->ifname, inet_ntoa(claim));
		ni_arp_send_grat_request(dev->arp.handle, claim);
		dev->arp.nclaims--;
	} else {
		/* Wow, we're done! */
		ni_info("%s: Successfully validated DHCPv4 address %s",
			dev->ifname, inet_ntoa(claim));
		ni_dhcp4_fsm_commit_lease(dev, dev->lease);
		ni_dhcp4_device_arp_close(dev);
		return 0;
	}

	ni_dhcp4_fsm_set_timeout_msec(dev, NI_DHCP4_ARP_TIMEOUT);
	return 0;
}
Beispiel #8
0
int
ni_dhcp4_fsm_validate_lease(ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease)
{
	/*
	 * When the address is already set on the link, we
	 * don't need to validate it and just commit it.
	 */
	if (__ni_dhcp4_address_on_link(dev, lease->dhcp4.address)) {
		ni_debug_dhcp("%s: address %s is on link, omit validation",
				dev->ifname, inet_ntoa(lease->dhcp4.address));
		ni_dhcp4_fsm_commit_lease(dev, lease);
		return 0;
	}

	ni_info("%s: Validating DHCPv4 address %s",
		dev->ifname, inet_ntoa(lease->dhcp4.address));

	/* For ARP validations, we will send 3 ARP queries with a timeout
	 * of 200ms each.
	 * The "claims" part is really for IPv4LL
	 */
	dev->arp.nprobes = 3;
	dev->arp.nclaims = 0;

	/* dhcp4cd source code says:
	 * IEEE1394 cannot set ARP target address according to RFC2734
	 */
	if (dev->system.hwaddr.type == ARPHRD_IEEE1394)
		dev->arp.nclaims = 0;

	if (ni_dhcp4_fsm_arp_validate(dev) < 0) {
		ni_debug_dhcp("%s: unable to validate lease", dev->ifname);
		return -1;
	}

	dev->fsm.state = NI_DHCP4_STATE_VALIDATING;
	return 0;
}
Beispiel #9
0
int
__ni_dhcp4_fsm_discover(ni_dhcp4_device_t *dev, int scan_offers)
{
	ni_addrconf_lease_t *lease;
	int rv;

	ni_info("%s: Initiating DHCPv4 discovery (ifindex %d)", dev->ifname, dev->link.ifindex);

	/* If we already have a lease, try asking for the same.
	 * If not, create a dummy lease with NULL fields.
	 * Note: if DISCOVER for the old lease times out,
	 * we should fall back to asking for anything.
	 */
	if ((lease = dev->lease) == NULL)
		lease = ni_addrconf_lease_new(NI_ADDRCONF_DHCP, AF_INET);
	lease->uuid = dev->config->uuid;

	dev->fsm.state = NI_DHCP4_STATE_SELECTING;
	rv = ni_dhcp4_device_send_message(dev, DHCP4_DISCOVER, lease);

	dev->dhcp4.accept_any_offer = 1;
	ni_debug_dhcp("valid lease: %d; have prefs: %d",
			ni_addrconf_lease_is_valid(dev->lease),
			ni_dhcp4_config_have_server_preference());
	if (ni_addrconf_lease_is_valid(dev->lease)
	 || (scan_offers && ni_dhcp4_config_have_server_preference())) {
		ni_dhcp4_fsm_set_timeout(dev, dev->config->initial_discovery_timeout);
		dev->dhcp4.accept_any_offer = 0;
	} else {
		ni_dhcp4_fsm_set_timeout(dev, dev->config->request_timeout);
	}

	ni_dhcp4_device_drop_best_offer(dev);

	if (lease != dev->lease)
		ni_addrconf_lease_free(lease);
	return rv;
}
Beispiel #10
0
void
ni_config_parse_update_targets(unsigned int *update_mask, const xml_node_t *node)
{
	const xml_node_t *child;

	*update_mask = __NI_ADDRCONF_UPDATE_NONE;
	for (child = node->children; child; child = child->next) {
		unsigned int target;

		if (!strcmp(child->name, "all")) {
			*update_mask = ni_config_addrconf_update_mask_all();
		} else
		if (!strcmp(child->name, "none")) {
			*update_mask = __NI_ADDRCONF_UPDATE_NONE;
		} else
		if (ni_addrconf_update_name_to_flag(child->name, &target)) {
			ni_addrconf_update_set(update_mask, target, TRUE);
		} else {
			ni_info("ignoring unknown addrconf update target \"%s\"",
					child->name);
		}
	}
}
Beispiel #11
0
static ni_socket_t *
__ni_rtevent_sock_open(void)
{
	unsigned int recv_buff_len = __ni_rtevent_config_recv_buff_len();
	unsigned int mesg_buff_len = __ni_rtevent_config_mesg_buff_len();
	ni_rtevent_handle_t *handle;
	ni_socket_t *sock;
	int fd, ret;

	if (!(handle = __ni_rtevent_handle_new())) {
		ni_error("Unable to allocate rtnetlink event handle: %m");
		return NULL;
	}

	if (!(handle->nlsock = nl_socket_alloc())) {
		ni_error("Cannot allocate rtnetlink event socket: %m");
		__ni_rtevent_handle_free(handle);
		return NULL;
	}

	/*
	 * Modify the callback for processing valid messages...
	 * We may pass some kind of data (event filter?) too...
	 */
	nl_socket_modify_cb(handle->nlsock, NL_CB_VALID, NL_CB_CUSTOM,
				__ni_rtevent_process_cb, NULL);

	/* Required to receive async event notifications */
	nl_socket_disable_seq_check(handle->nlsock);

	if ((ret = nl_connect(handle->nlsock, NETLINK_ROUTE)) < 0) {
		ni_error("Cannot open rtnetlink: %s", nl_geterror(ret));
		__ni_rtevent_handle_free(handle);
		return NULL;
	}

	/* Enable non-blocking processing */
	nl_socket_set_nonblocking(handle->nlsock);

	fd = nl_socket_get_fd(handle->nlsock);
	if (!(sock = ni_socket_wrap(fd, SOCK_DGRAM))) {
		ni_error("Cannot wrap rtnetlink event socket: %m");
		__ni_rtevent_handle_free(handle);
		return NULL;
	}

	if (recv_buff_len) {
		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE,
				(char *)&recv_buff_len, sizeof(recv_buff_len)) &&
		    setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
				(char *)&recv_buff_len, sizeof(recv_buff_len))) {
			ni_warn("Unable to set netlink event receive buffer to %u bytes: %m",
					recv_buff_len);
		} else {
			ni_info("Using netlink event receive buffer of %u bytes",
					recv_buff_len);
		}
	}
	if (mesg_buff_len) {
		if (nl_socket_set_msg_buf_size(handle->nlsock, mesg_buff_len)) {
			ni_warn("Unable to set netlink event message buffer to %u bytes",
					mesg_buff_len);
		} else {
			ni_info("Using netlink event message buffer of %u bytes",
					mesg_buff_len);
		}
	}

	sock->user_data	= handle;
	sock->receive	= __ni_rtevent_receive;
	sock->close	= __ni_rtevent_close;
	sock->handle_error  = __ni_rtevent_sock_error_handler;
	sock->release_user_data = __ni_rtevent_sock_release_data;
	return sock;
}
Beispiel #12
0
static void
__do_arp_validate_process(ni_arp_socket_t *sock, const ni_arp_packet_t *pkt,
		void *user_data)
{
	struct arp_handle *handle = user_data;
	ni_netconfig_t *nc = ni_global_state_handle(0);
	const ni_netdev_t *ifp;
	ni_bool_t false_alarm = FALSE;
	ni_bool_t found_addr = FALSE;
	const ni_address_t *ap;
	ni_sockaddr_t addr;

	if (!pkt || pkt->op != ARPOP_REPLY || !handle->replies)
		return;

	/* Is it about the address we're validating at all? */
	if (pkt->sip.s_addr != handle->ipaddr.sin.sin_addr.s_addr) {
		ni_debug_application("%s: report about different address",
				handle->ifname);
		return;
	}

	/* Ignore any ARP replies that seem to come from our own
	 * MAC address. Some helpful switches seem to generate
	 * these. */
	if (ni_link_address_equal(&sock->dev_info.hwaddr, &pkt->sha)) {
		ni_debug_application("%s: adress in use by ourself",
				handle->ifname);
		return;
	}

	/* As well as ARP replies that seem to come from our own
	 * host: dup if same address, not a dup if there are two
	 * interfaces connected to the same broadcast domain.
	 */
	ni_sockaddr_set_ipv4(&addr, pkt->sip, 0);
	for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) {
		if (ifp->link.ifindex == sock->dev_info.ifindex)
			continue;

		if (!ni_netdev_link_is_up(ifp))
			continue;

		if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha))
			continue;

		/* OK, we have an interface matching the hwaddr,
		 * which will answer arp requests when it is on
		 * the same broadcast domain and causes a false
		 * alarm, except it really has the IP assigned.
		 */
		false_alarm = TRUE;
		for (ap = ifp->addrs; !found_addr && ap; ap = ap->next) {
			if (ap->family != AF_INET)
				continue;
			if (ni_sockaddr_equal(&ap->local_addr, &addr))
				found_addr = TRUE;
		}
	}
	if (false_alarm && !found_addr) {
		ni_debug_application("%s: reply from one of our interfaces",
				handle->ifname);
		return;
	}

	ni_info("%s: adress %s in use by %s reported",
			handle->ifname,
			inet_ntoa(pkt->sip),
			ni_link_address_print(&pkt->sha));
	handle->hwaddr = pkt->sha;
}
Beispiel #13
0
/*
 * Install information from a lease, and remember that we did
 */
static ni_bool_t
ni_system_updater_install(ni_updater_t *updater, const ni_addrconf_lease_t *lease, const char *ifname)
{
	ni_string_array_t arguments = NI_STRING_ARRAY_INIT;
	const char *statedir = NULL;
	char *file = NULL;
	ni_bool_t result = FALSE;
	int rv = 0;

	ni_debug_ifconfig("Updating system %s settings from %s/%s lease",
					ni_updater_name(updater->kind),
					ni_addrconf_type_to_name(lease->type),
					ni_addrfamily_type_to_name(lease->family));

	if (!updater->proc_install)
		return TRUE;

	if (!ifname || (!updater->have_backup && !ni_system_updater_backup(updater, ifname)))
		return FALSE;

	ni_string_array_append(&arguments, "-i");
	ni_string_array_append(&arguments, ifname);

	ni_string_array_append(&arguments, "-t");
	ni_string_array_append(&arguments, ni_addrconf_type_to_name(lease->type));

	ni_string_array_append(&arguments, "-f");
	ni_string_array_append(&arguments, ni_addrfamily_type_to_name(lease->family));

	switch (updater->kind) {
	case NI_ADDRCONF_UPDATER_GENERIC:
		switch (updater->format) {
		case NI_ADDRCONF_UPDATER_FORMAT_INFO:
			ni_leaseinfo_dump(NULL, lease, ifname, NULL);
			if (!(file = ni_leaseinfo_path(ifname, lease->type, lease->family))) {
				ni_error("Unable to determine leaseinfo file path.");
				goto done;
			}
			ni_string_array_append(&arguments, file);
			break;

		default:
			ni_error("Unsupported %s updater data format.",
				ni_updater_name(updater->kind));
			goto done;
		}

		ni_string_array_append(&arguments,
				ni_updater_format_name(updater->format));
		break;

	case NI_ADDRCONF_UPDATER_RESOLVER:
		statedir = ni_extension_statedir(ni_updater_name(updater->kind));
		if (!statedir) {
			ni_error("failed to get %s statedir", ni_updater_name(updater->kind));
			goto done;
		}
		ni_string_printf(&file, "%s/resolv.conf.%s.%s.%s",
				statedir, ifname,
				ni_addrconf_type_to_name(lease->type),
				ni_addrfamily_type_to_name(lease->family));
		ni_string_array_append(&arguments, file);

		if ((rv = ni_resolver_write_resolv_conf(file, lease->resolver, NULL)) < 0) {
			ni_error("failed to write resolver info to file: %s",
					ni_strerror(rv));
			goto done;
		}
		break;

	case NI_ADDRCONF_UPDATER_HOSTNAME:
		if (!ni_string_empty(lease->hostname)) {
			ni_string_array_append(&arguments, lease->hostname);
		} else {
			const ni_address_t *ap;
			char *name = NULL;
			unsigned int count;

			/* bnc#861476 workaround */
			if (!can_try_reverse_lookup(lease))
				goto done;

			for (count = 0, ap = lease->addrs; ap; ap = ap->next) {
				if (!ni_sockaddr_is_specified(&ap->local_addr))
					continue;

				if (!ni_resolve_reverse_timed(&ap->local_addr,
						&name, NI_UPDATER_REVERSE_TIMEOUT))
					break;

				ni_info("Unable to resolve %s to hostname",
					ni_sockaddr_print(&ap->local_addr));

				if (++count >= NI_UPDATER_REVERSE_MAX_CNT)
					break;
			}

			if (ni_string_empty(name)) {
				ni_note("Skipping hostname update, none available");
				goto done;
			}
			ni_string_array_append(&arguments, name);
			ni_string_free(&name);
		}
		break;

	default:
		ni_error("cannot install new %s settings - file format not understood",
				ni_updater_name(updater->kind));
		goto done;
	}

	if (!ni_system_updater_run(updater->proc_install, &arguments)) {
		ni_error("failed to install %s settings", ni_updater_name(updater->kind));
		goto done;
	}

	result = TRUE;

	switch (updater->kind) {
	case NI_ADDRCONF_UPDATER_RESOLVER:
		if (ni_global.other_event)
			ni_global.other_event(NI_EVENT_RESOLVER_UPDATED);
		break;

	case NI_ADDRCONF_UPDATER_HOSTNAME:
		if (ni_global.other_event)
			ni_global.other_event(NI_EVENT_HOSTNAME_UPDATED);
		break;

	case NI_ADDRCONF_UPDATER_GENERIC:
		if (ni_global.other_event)
			ni_global.other_event(NI_EVENT_GENERIC_UPDATED);
		break;

	default:
		break;
	}

done:
	if (file)
		free(file);
	ni_string_array_destroy(&arguments);

	return result;
}
Beispiel #14
0
static int
__ni_dhcp4_build_msg_put_our_hostname(const ni_dhcp4_device_t *dev,
					ni_buffer_t *msgbuf)
{
	const ni_dhcp4_config_t *options = dev->config;
	size_t len = ni_string_len(options->hostname);

	if (!len)
		return 1; /* skipped hint */

	if (options->fqdn == FQDN_DISABLE) {
		char hname[64] = {'\0'}, *end;

		/*
		 * Truncate the domain part if fqdn to avoid attempts
		 * to update DNS with foo.bar + update-domain.
		 */
		strncat(hname, options->hostname, sizeof(hname)-1);
		if ((end = strchr(hname, '.')))
			*end = '\0';

		len = ni_string_len(hname);
		if (ni_check_domain_name(hname, len, 0)) {
			ni_dhcp4_option_puts(msgbuf, DHCP4_HOSTNAME, hname);
			ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: using hostname: %s", dev->ifname, hname);
		} else {
			ni_info("%s: not sending suspect hostname: '%s'",
				dev->ifname, ni_print_suspect(hname, len));
			return 1;
		}
	} else
	if (ni_check_domain_name(options->hostname, len, 0)) {
		/* IETF DHC-FQDN option(81)
		 * http://tools.ietf.org/html/rfc4702#section-2.1
		 *
		 * Flags: 0000NEOS
		 * S: 1 => Client requests Server to update
		 *         a RR in DNS as well as PTR
		 * O: 1 => Server indicates to client that
		 *         DNS has been updated
		 * E: 1 => Name data is DNS format
		 * N: 1 => Client requests Server to not
		 *         update DNS
		 */
		ni_buffer_putc(msgbuf, DHCP4_FQDN);
		ni_buffer_putc(msgbuf, len + 3);
		ni_buffer_putc(msgbuf, options->fqdn & 0x9);
		ni_buffer_putc(msgbuf, 0);	/* from server for PTR RR */
		ni_buffer_putc(msgbuf, 0);	/* from server for A RR if S=1 */
		ni_buffer_put(msgbuf, options->hostname, len);
		ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: using fqdn: %s", dev->ifname,
				options->hostname);
	} else {
		ni_info("%s: not sending suspect fqdn: '%s'",
			dev->ifname, ni_print_suspect(options->hostname, len));
		return 1;
	}

	return 0;
}