示例#1
0
/*
 * Generic functions for static address configuration
 */
static dbus_bool_t
ni_objectmodel_addrconf_static_request(ni_dbus_object_t *object, unsigned int addrfamily,
			unsigned int argc, const ni_dbus_variant_t *argv,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_addrconf_lease_t *lease = NULL;
	const ni_dbus_variant_t *dict;
	const char *string_value;
	ni_netdev_t *dev;
	ni_address_t *ap;
	int rv;

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	if (argc != 1 || !ni_dbus_variant_is_dict(&argv[0])) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
				"requestLease: expected one dict argument");
		return FALSE;
	}
	dict = &argv[0];

	lease = ni_addrconf_lease_new(NI_ADDRCONF_STATIC, addrfamily);
	lease->state = NI_ADDRCONF_STATE_GRANTED;
	ni_uuid_generate(&lease->uuid);

	if (!__ni_objectmodel_set_address_dict(&lease->addrs, dict, error)
	 || !__ni_objectmodel_set_route_dict(&lease->routes, dict, error)
	 || !__ni_objectmodel_set_resolver_dict(&lease->resolver, dict, error)) {
		ni_addrconf_lease_free(lease);
		return FALSE;
	}
	if (__ni_objectmodel_get_domain_string(dict, "hostname", &string_value))
		ni_string_dup(&lease->hostname, string_value);

	/* mark all addresses tentative, causing to verify them */
	for (ap = lease->addrs; ap; ap = ap->next)
		ni_address_set_tentative(ap, TRUE);

	rv = __ni_system_interface_update_lease(dev, &lease);
	if (lease)
		ni_addrconf_lease_free(lease);

	if (rv < 0) {
		dbus_set_error(error,
				DBUS_ERROR_FAILED,
				"Error configuring static %s addresses: %s",
				ni_addrfamily_type_to_name(addrfamily),
				ni_strerror(rv));
		return FALSE;
	}

	/* Don't return anything. */
	return TRUE;
}
示例#2
0
static dbus_bool_t
ni_objectmodel_addrconf_static_drop(ni_dbus_object_t *object, unsigned int addrfamily,
			ni_dbus_message_t *reply, DBusError *error)
{
	ni_addrconf_lease_t *lease = NULL;
	ni_netdev_t *dev;
	int rv;

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)))
		return FALSE;

	lease = ni_addrconf_lease_new(NI_ADDRCONF_STATIC, addrfamily);
	lease->state = NI_ADDRCONF_STATE_RELEASED;

	rv = __ni_system_interface_update_lease(dev, &lease);
	if (lease)
		ni_addrconf_lease_free(lease);

	if (rv < 0) {
		dbus_set_error(error,
				DBUS_ERROR_FAILED,
				"Error dropping static %s addresses: %s",
				ni_addrfamily_type_to_name(addrfamily),
				ni_strerror(rv));
		return FALSE;
	}

	/* Don't return anything */
	return TRUE;
}
示例#3
0
void
ni_addrconf_lease_destroy(ni_addrconf_lease_t *lease)
{
	ni_addrconf_updater_free(&lease->updater);
	if (lease->old) {
		ni_addrconf_lease_free(lease->old);
		lease->old = NULL;
	}

	ni_string_free(&lease->owner);
	ni_string_free(&lease->hostname);

	ni_address_list_destroy(&lease->addrs);
	ni_route_tables_destroy(&lease->routes);

	if (lease->nis) {
		ni_nis_info_free(lease->nis);
		lease->nis = NULL;
	}
	if (lease->resolver) {
		ni_resolver_info_free(lease->resolver);
		lease->resolver = NULL;
	}

	ni_string_array_destroy(&lease->ntp_servers);
	ni_string_array_destroy(&lease->nds_servers);
	ni_string_array_destroy(&lease->nds_context);
	ni_string_free(&lease->nds_tree);
	ni_string_array_destroy(&lease->netbios_name_servers);
	ni_string_array_destroy(&lease->netbios_dd_servers);
	ni_string_free(&lease->netbios_scope);
	ni_string_array_destroy(&lease->slp_servers);
	ni_string_array_destroy(&lease->slp_scopes);
	ni_string_array_destroy(&lease->sip_servers);
	ni_string_array_destroy(&lease->lpr_servers);
	ni_string_array_destroy(&lease->log_servers);

	ni_string_free(&lease->posix_tz_string);
	ni_string_free(&lease->posix_tz_dbname);

	switch (lease->type) {
	case NI_ADDRCONF_DHCP:

		switch (lease->family) {
		case AF_INET:
			ni_addrconf_lease_dhcp4_destroy(&lease->dhcp4);
			break;

		case AF_INET6:
			ni_addrconf_lease_dhcp6_destroy(&lease->dhcp6);
			break;

		default: ;
		}

		break;

	default: ;
	}
}
示例#4
0
文件: device.c 项目: mijos/wicked
void
ni_dhcp4_device_drop_best_offer(ni_dhcp4_device_t *dev)
{
	dev->best_offer.weight = -1;
	if (dev->best_offer.lease)
		ni_addrconf_lease_free(dev->best_offer.lease);
	dev->best_offer.lease = NULL;
}
示例#5
0
int
ni_netdev_unset_lease(ni_netdev_t *dev, unsigned int family, ni_addrconf_mode_t type)
{
	ni_addrconf_lease_t *lease;

	if ((lease = __ni_netdev_find_lease(dev, family, type, 1)) != NULL)
		ni_addrconf_lease_free(lease);
	return 0;
}
示例#6
0
文件: device.c 项目: kmroz/wicked
void
ni_autoip_device_set_lease(ni_autoip_device_t *dev, ni_addrconf_lease_t *lease)
{
	if (dev->lease != lease) {
		if (dev->lease)
			ni_addrconf_lease_free(dev->lease);
		dev->lease = lease;
	}
}
示例#7
0
int
ni_dhcp4_fsm_recover_lease(ni_dhcp4_device_t *dev, const ni_dhcp4_request_t *req)
{
	ni_addrconf_lease_t *lease;
	time_t now = time(NULL), then;

	/* Don't recover anything if we already have a lease attached. */
	if (dev->lease != NULL)
		return -1;

	lease = ni_addrconf_lease_file_read(dev->ifname, NI_ADDRCONF_DHCP, AF_INET);
	if (!lease)
		return -1;

	if (lease->state != NI_ADDRCONF_STATE_GRANTED)
		goto discard;

	ni_debug_dhcp("trying to recover dhcp4 lease, now inspecting");
	then = lease->time_acquired;
	if (now < then) {
		ni_debug_dhcp("%s: found time-warped lease (hi, grand-grand-pa)", __FUNCTION__);
		goto discard;
	}

	if (now >= then + lease->dhcp4.lease_time) {
		ni_debug_dhcp("%s: found expired lease", __FUNCTION__);
		goto discard;
	}

	if ((req->hostname && !ni_string_eq(req->hostname, dev->lease->hostname))
	 || (req->clientid && !ni_string_eq(req->clientid, dev->lease->dhcp4.client_id))) {
		ni_debug_dhcp("%s: lease doesn't match request", __FUNCTION__);
		goto discard;
	}

	ni_dhcp4_device_set_lease(dev, lease);

	if (now >= then + lease->dhcp4.rebind_time) {
		ni_dhcp4_fsm_rebind(dev);
	} else
	if (now >= then + lease->dhcp4.renewal_time) {
		ni_dhcp4_fsm_renewal(dev);
	} else {
		ni_dhcp4_fsm_set_deadline(dev, then + lease->dhcp4.renewal_time);
		dev->fsm.state = NI_DHCP4_STATE_BOUND;
	}

	ni_debug_dhcp("%s: recovered old lease; now in state=%s",
			dev->ifname, ni_dhcp4_fsm_state_name(dev->fsm.state));
	dev->notify = 1;
	return 0;

discard:
	ni_addrconf_lease_free(lease);
	return -1;
}
示例#8
0
void
ni_addrconf_lease_list_destroy(ni_addrconf_lease_t **list)
{
	ni_addrconf_lease_t *lease;

	while ((lease = *list) != NULL) {
		*list = lease->next;
		ni_addrconf_lease_free(lease);
	}
}
示例#9
0
文件: leasefile.c 项目: gsanso/wicked
int
ni_addrconf_lease_from_xml(ni_addrconf_lease_t **leasep, const xml_node_t *root)
{
	const xml_node_t *node = root;
	ni_addrconf_lease_t *lease;
	int ret = -1;

	if (root && !ni_string_eq(root->name, NI_ADDRCONF_LEASE_XML_NODE))
		node = xml_node_get_child(root, NI_ADDRCONF_LEASE_XML_NODE);

	if (!node || !leasep)
		return ret;

	*leasep = NULL; /* initialize... */
	if (!(lease  = ni_addrconf_lease_new(__NI_ADDRCONF_MAX, AF_UNSPEC)))
		return ret;

	if ((ret = __ni_addrconf_lease_info_from_xml(lease, node)) != 0) {
		ni_addrconf_lease_free(lease);
		return ret;
	}

	switch (lease->type) {
	case NI_ADDRCONF_STATIC:
	case NI_ADDRCONF_AUTOCONF:
	case NI_ADDRCONF_INTRINSIC:
		ret = __ni_addrconf_lease_static_from_xml(lease, node);
		break;

	case NI_ADDRCONF_DHCP:
		ret = __ni_addrconf_lease_dhcp_from_xml(lease, node);
		break;
	default: ;		/* fall through error */
	}

	if (ret) {
		ni_addrconf_lease_free(lease);
	} else {
		*leasep = lease;
	}
	return ret;
}
示例#10
0
文件: device.c 项目: mijos/wicked
void
ni_dhcp4_device_set_best_offer(ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease,
							int weight)
{
	if (dev->best_offer.lease && dev->best_offer.lease != lease)
		ni_addrconf_lease_free(dev->best_offer.lease);
	dev->best_offer.lease = lease;
	dev->best_offer.weight = weight;
	if (dev->config && lease)
		lease->uuid = dev->config->uuid;
}
示例#11
0
文件: device.c 项目: mijos/wicked
void
ni_dhcp4_device_set_lease(ni_dhcp4_device_t *dev, ni_addrconf_lease_t *lease)
{
	if (dev->lease != lease) {
		if (dev->lease)
			ni_addrconf_lease_free(dev->lease);
		dev->lease = lease;
		if (dev->config && lease)
			lease->uuid = dev->config->uuid;
	}
}
示例#12
0
文件: device.c 项目: mijos/wicked
void
ni_dhcp4_device_drop_lease(ni_dhcp4_device_t *dev)
{
	ni_addrconf_lease_t *lease;

	if ((lease = dev->lease) != NULL) {
		ni_addrconf_lease_free(lease);
		dev->lease = NULL;

		/* Go back to square one */
		dev->fsm.state = NI_DHCP4_STATE_INIT;
	}
}
示例#13
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;
}
示例#14
0
/*
 * Reload an old lease from file, and see whether we can reuse it.
 * This is used during restart of wickedd.
 */
int
ni_dhcp4_recover_lease(ni_dhcp4_device_t *dev)
{
	ni_addrconf_lease_t *lease;
	ni_sockaddr_t addr;

	if (dev->lease)
		return 1;

	lease = ni_addrconf_lease_file_read(dev->ifname, NI_ADDRCONF_DHCP, AF_INET);
	if (!lease)
		return -1;

	if (!ni_addrconf_lease_is_valid(dev->lease)) {
		ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: discarding existing lease, not granted",
				dev->ifname);
		goto discard;
	}

	/* We cannot renew/rebind/reboot without it */
	ni_sockaddr_set_ipv4(&addr, lease->dhcp4.server_id, 0);
	if (!ni_sockaddr_is_ipv4_specified(&addr)) {
		ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP,
				"%s: discarding existing lease, no server-id",
				dev->ifname);
		goto discard;
	}

	ni_dhcp4_device_set_lease(dev, lease);
	return 0;

discard:
	ni_addrconf_lease_free(lease);
	return -1;
}
示例#15
0
/*
 * Callback from addrconf supplicant whenever it acquired, released or lost a lease.
 *
 * FIXME SECURITY:
 * Is it good enough to check for the sender interface to avoid that someone is sending
 * us spoofed lease messages?!
 */
void
ni_objectmodel_addrconf_signal_handler(ni_dbus_connection_t *conn, ni_dbus_message_t *msg, void *user_data)
{
	ni_dbus_addrconf_forwarder_t *forwarder = user_data;
	const char *signal_name = dbus_message_get_member(msg);
	ni_netdev_t *ifp;
	ni_addrconf_lease_t *lease = NULL;
	ni_dbus_variant_t argv[16];
	ni_uuid_t uuid = NI_UUID_INIT;
	ni_event_t ifevent;
	int argc, optind = 0;

	memset(argv, 0, sizeof(argv));
	argc = ni_dbus_message_get_args_variants(msg, argv, 16);
	if (argc < 0) {
		ni_error("%s: cannot parse arguments for signal %s", __func__, signal_name);
		goto done;
	}

	ifp = ni_objectmodel_addrconf_path_to_device(dbus_message_get_path(msg));
	if (ifp == NULL) {
		ni_debug_dbus("%s: received signal %s for unknown interface %s", __func__,
				signal_name, dbus_message_get_path(msg));
		goto done;
	}

	lease = ni_addrconf_lease_new(forwarder->addrconf, forwarder->addrfamily);

	if (argc != 1 && argc != 2) {
		ni_warn("%s: ignoring %s event from %s: bad number of arguments (%u)",
				__func__, signal_name, dbus_message_get_path(msg), argc);
		goto done;
	}

	if (argc == 2 && !ni_dbus_variant_get_uuid(&argv[optind++], &uuid)) {
		ni_debug_dbus("%s: unable to parse uuid argument", __func__);
		goto done;
	}

	if (!ni_objectmodel_set_addrconf_lease(lease, &argv[optind++])) {
		ni_error("%s: unable to parse lease argument received from %s", __func__,
				dbus_message_get_sender(msg));
		goto done;
	}

	ni_debug_dbus("received signal %s for interface %s (ifindex %d), lease %s:%s, uuid=%s, update=0x%x, flags=0x%x",
			signal_name, ifp->name, ifp->link.ifindex,
			ni_addrfamily_type_to_name(lease->family),
			ni_addrconf_type_to_name(lease->type),
			ni_uuid_print(&uuid), lease->update, lease->flags);
	if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_ACQUIRED_SIGNAL)) {
		if (lease->state != NI_ADDRCONF_STATE_GRANTED) {
			ni_error("%s: unexpected lease state in signal %s", __func__, signal_name);
			goto done;
		}

		ifevent = NI_EVENT_ADDRESS_ACQUIRED;

		if (!__ni_addrconf_should_update(lease->update, NI_ADDRCONF_UPDATE_DEFAULT_ROUTE)) {
			ni_route_table_t *tab;
			ni_route_t *rp;
			unsigned int i;

			for (tab = lease->routes; tab; tab = tab->next) {
				for (i = 0; i < tab->routes.count; ++i) {
					if (!(rp = tab->routes.data[i]))
						continue;

					if (ni_sockaddr_is_specified(&rp->destination))
						continue;

					if (ni_route_array_delete(&tab->routes, i))
						i--;
				}
			}
		}
	} else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_RELEASED_SIGNAL)) {
		lease->state = NI_ADDRCONF_STATE_RELEASED;
		ifevent = NI_EVENT_ADDRESS_RELEASED;
	} else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_LOST_SIGNAL)) {
		lease->state = NI_ADDRCONF_STATE_FAILED;
		ifevent = NI_EVENT_ADDRESS_LOST;
	} else {
		/* Ignore unknown signal */
		goto done;
	}

	/*
	 * The following call updates the system with the information given in
	 * the lease. This includes setting all addresses, as well as updating
	 * resolver and hostname, if provided.
	 * When a lease is dropped, we either fall back to the config information
	 * from the next best lease, or if there is none, we restore the original
	 * system settings.
	 *
	 * Note, lease may be NULL after this, as the interface object
	 * takes ownership of it.
	 */
	__ni_system_interface_update_lease(ifp, &lease);

	/* Potentially, there's a client somewhere waiting for that event.
	 * We use the UUID that's passed back and forth to make sure we
	 * really match the event we were expecting to match.
	 */
	{
		ni_dbus_object_t *object;

		object = ni_objectmodel_get_netif_object(__ni_objectmodel_server, ifp);
		if (object)
			ni_objectmodel_send_netif_event(__ni_objectmodel_server, object,
					ifevent, ni_uuid_is_null(&uuid)? NULL : &uuid);
	}

done:
	while (argc--)
		ni_dbus_variant_destroy(&argv[argc]);
	if (lease)
		ni_addrconf_lease_free(lease);
}
示例#16
0
int
ni_dhcp4_fsm_process_dhcp4_packet(ni_dhcp4_device_t *dev, ni_buffer_t *msgbuf)
{
	ni_dhcp4_message_t *message;
	ni_addrconf_lease_t *lease = NULL;
	int msg_code;

	if (dev->fsm.state == NI_DHCP4_STATE_VALIDATING) {
		/* We arrive here, when some dhcp4 packet arrives after
		 * we've got and processed an ACK already. Just ignore.
		 */
		ni_debug_dhcp("%s: ignoring dhcp4 packet arrived in state VALIDATING",
				dev->ifname);
		return -1;
	}

	if (!(message = ni_buffer_pull_head(msgbuf, sizeof(*message)))) {
		ni_debug_dhcp("short DHCP4 packet (%u bytes)", ni_buffer_count(msgbuf));
		return -1;
	}
	if (dev->dhcp4.xid == 0) {
		ni_debug_dhcp("unexpected packet on %s", dev->ifname);
		return -1;
	}
	if (dev->dhcp4.xid != message->xid) {
		ni_debug_dhcp("ignoring packet with wrong xid 0x%x (expected 0x%x)",
				message->xid, dev->dhcp4.xid);
		return -1;
	}

	msg_code = ni_dhcp4_parse_response(message, msgbuf, &lease);
	if (msg_code < 0) {
		/* Ignore this message, time out later */
		ni_error("unable to parse DHCP4 response");
		return -1;
	}

	/* set reqest client-id in the response early to have it in test mode */
	ni_opaque_set(&lease->dhcp4.client_id,	dev->config->client_id.data,
						dev->config->client_id.len);

	ni_debug_dhcp("%s: received %s message in state %s",
			dev->ifname, ni_dhcp4_message_name(msg_code),
			ni_dhcp4_fsm_state_name(dev->fsm.state));

	/* When receiving a DHCP4 OFFER, verify sender address against list of
	 * servers to ignore, and preferred servers. */
	if (msg_code == DHCP4_OFFER && dev->fsm.state == NI_DHCP4_STATE_SELECTING) {
		struct in_addr srv_addr = lease->dhcp4.server_id;
		int weight = 0;

		if (ni_dhcp4_config_ignore_server(srv_addr)) {
			ni_debug_dhcp("%s: ignoring DHCP4 offer from %s",
					dev->ifname, inet_ntoa(srv_addr));
			goto out;
		}

		/* If we're scanning all offers, we need to decide whether
		 * this offer is accepted, or whether we want to wait for
		 * more.
		 */
		if (!dev->dhcp4.accept_any_offer) {

			/* Check if we have any preferred servers. */
			weight = ni_dhcp4_config_server_preference(srv_addr);

			/* If we're refreshing an existing lease (eg after link disconnect
			 * and reconnect), we accept the offer if it comes from the same
			 * server as the original one.
			 */
			if (dev->lease
			 && dev->lease->dhcp4.server_id.s_addr == srv_addr.s_addr)
				weight = 100;

			ni_debug_dhcp("received lease offer from %s; server weight=%d (best offer=%d)",
					inet_ntoa(lease->dhcp4.server_id), weight,
					dev->best_offer.weight);

			/* negative weight means never. */
			if (weight < 0)
				goto out;

			/* weight between 0 and 100 means maybe. */
			if (weight < 100) {
				if (dev->best_offer.weight < weight) {
					ni_dhcp4_device_set_best_offer(dev, lease, weight);
					return 0;
				}
				goto out;
			}
			/* If the weight has maximum value, just accept this offer. */
		}
		ni_dhcp4_device_set_best_offer(dev, lease, weight);
		lease = NULL;
	}

	/* We've received a valid response; if something goes wrong now
	 * it's nothing that could be fixed by retransmitting the message.
	 *
	 * The only exception would be if we ever do some filtering or
	 * matching of OFFERs - then we would certainly want to keep
	 * waiting for additional packets.
	 */
	ni_dhcp4_device_disarm_retransmit(dev);
	dev->dhcp4.xid = 0;

	/* move to next stage of protocol */
	switch (msg_code) {
	case DHCP4_OFFER:
		if (dev->fsm.state != NI_DHCP4_STATE_SELECTING)
			goto ignore;

		/* process best offer set above */
		ni_dhcp4_process_offer(dev, dev->best_offer.lease);
		break;

	case DHCP4_ACK:
		if (dev->fsm.state == NI_DHCP4_STATE_INIT) {
			/*
			 * Received a decline ACK -- wait until
			 * timeout before we restart from begin
			 */
			ni_dhcp4_device_drop_lease(dev);
			break;
		}

		if (dev->fsm.state != NI_DHCP4_STATE_REQUESTING
		 && dev->fsm.state != NI_DHCP4_STATE_RENEWING
		 && dev->fsm.state != NI_DHCP4_STATE_REBOOT
		 && dev->fsm.state != NI_DHCP4_STATE_REBINDING)
			goto ignore;

		ni_dhcp4_process_ack(dev, lease);
		lease = NULL;
		break;

	case DHCP4_NAK:
		/* The RFC 2131 state diagram says, ignore NAKs in state BOUND.
		 * I guess we also have no use for NAK replies to a DHCP4_DISCOVER
		 */
		if (dev->fsm.state == NI_DHCP4_STATE_SELECTING
		 || dev->fsm.state == NI_DHCP4_STATE_BOUND)
			goto ignore;

		ni_dhcp4_process_nak(dev);
		break;

	default:
	ignore:
		ni_debug_dhcp("ignoring %s in state %s",
				ni_dhcp4_message_name(msg_code),
				ni_dhcp4_fsm_state_name(dev->fsm.state));
		break;
	}

out:
	if (lease && dev->lease != lease)
		ni_addrconf_lease_free(lease);

	/* If we received a message other than NAK, reset the NAK
	 * backoff timer. */
	if (msg_code != DHCP4_NAK)
		dev->dhcp4.nak_backoff = 1;

	return 0;
}