Example #1
0
static void provider_resolv_host_addr(struct vpn_provider *provider)
{
	if (provider->host == NULL)
		return;

	if (connman_inet_check_ipaddress(provider->host) > 0)
		return;

	if (provider->host_ip != NULL)
		return;

	/*
	 * If the hostname is not numeric, try to resolv it. We do not wait
	 * the result as it might take some time. We will get the result
	 * before VPN will feed routes to us because VPN client will need
	 * the IP address also before VPN connection can be established.
	 */
	provider->resolv = g_resolv_new(0);
	if (provider->resolv == NULL) {
		DBG("Cannot resolv %s", provider->host);
		return;
	}

	DBG("Trying to resolv %s", provider->host);

	vpn_provider_ref(provider);

	g_resolv_lookup_hostname(provider->resolv, provider->host,
				resolv_result, provider);
}
Example #2
0
static int vpn_connect(struct vpn_provider *provider,
			vpn_provider_connect_cb_t cb,
			const char *dbus_sender, void *user_data)
{
	struct vpn_data *data = vpn_provider_get_data(provider);
	struct vpn_driver_data *vpn_driver_data;
	const char *name;
	int ret = 0;
	enum vpn_state state = VPN_STATE_UNKNOWN;

	if (data)
		state = data->state;

	DBG("data %p state %d", data, state);

	switch (state) {
	case VPN_STATE_UNKNOWN:
		data = g_try_new0(struct vpn_data, 1);
		if (!data)
			return -ENOMEM;

		data->provider = vpn_provider_ref(provider);
		data->watch = 0;
		data->flags = 0;
		data->task = NULL;

		vpn_provider_set_data(provider, data);
		/* fall through */

	case VPN_STATE_DISCONNECT:
	case VPN_STATE_IDLE:
	case VPN_STATE_FAILURE:
	case VPN_STATE_AUTH_FAILURE:
		data->state = VPN_STATE_IDLE;
		break;

	case VPN_STATE_CONNECT:
		return -EINPROGRESS;

	case VPN_STATE_READY:
		return -EISCONN;
	}

	name = vpn_provider_get_driver_name(provider);
	if (!name)
		return -EINVAL;

	vpn_driver_data = g_hash_table_lookup(driver_hash, name);

	if (!vpn_driver_data || !vpn_driver_data->vpn_driver) {
		ret = -EINVAL;
		goto exist_err;
	}

	if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
		ret = vpn_create_tun(provider);
		if (ret < 0)
			goto exist_err;
	}

	data->task = connman_task_create(vpn_driver_data->program);

	if (!data->task) {
		ret = -ENOMEM;
		stop_vpn(provider);
		goto exist_err;
	}

	if (connman_task_set_notify(data->task, "notify",
					vpn_notify, provider)) {
		ret = -ENOMEM;
		stop_vpn(provider);
		connman_task_destroy(data->task);
		data->task = NULL;
		goto exist_err;
	}

	ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
						data->if_name, cb, dbus_sender,
						user_data);
	if (ret < 0 && ret != -EINPROGRESS) {
		stop_vpn(provider);
		connman_task_destroy(data->task);
		data->task = NULL;
		goto exist_err;
	}

	DBG("%s started with dev %s",
		vpn_driver_data->provider_driver.name, data->if_name);

	data->state = VPN_STATE_CONNECT;

	return -EINPROGRESS;

exist_err:
	vpn_provider_set_index(provider, -1);
	vpn_provider_set_data(provider, NULL);
	vpn_provider_unref(data->provider);
	g_free(data->if_name);
	g_free(data);

	return ret;
}
Example #3
0
static DBusMessage *vpn_notify(struct connman_task *task,
			DBusMessage *msg, void *user_data)
{
	struct vpn_provider *provider = user_data;
	struct vpn_data *data;
	struct vpn_driver_data *vpn_driver_data;
	const char *name;
	int state, index, err;

	data = vpn_provider_get_data(provider);

	name = vpn_provider_get_driver_name(provider);

	if (!name) {
		DBG("Cannot find VPN driver for provider %p", provider);
		vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
		return NULL;
	}

	vpn_driver_data = g_hash_table_lookup(driver_hash, name);
	if (!vpn_driver_data) {
		DBG("Cannot find VPN driver data for name %s", name);
		vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
		return NULL;
	}

	state = vpn_driver_data->vpn_driver->notify(msg, provider);

	DBG("provider %p driver %s state %d", provider, name, state);

	switch (state) {
	case VPN_STATE_CONNECT:
	case VPN_STATE_READY:
		if (data->state == VPN_STATE_READY) {
			/*
			 * This is the restart case, in which case we must
			 * just set the IP address.
			 *
			 * We need to remove first the old address, just
			 * replacing the old address will not work as expected
			 * because the old address will linger in the interface
			 * and not disapper so the clearing is needed here.
			 *
			 * Also the state must change, otherwise the routes
			 * will not be set properly.
			 */
			vpn_provider_set_state(provider,
						VPN_PROVIDER_STATE_CONNECT);

			vpn_provider_clear_address(provider, AF_INET);
			vpn_provider_clear_address(provider, AF_INET6);

			vpn_provider_change_address(provider);
			vpn_provider_set_state(provider,
						VPN_PROVIDER_STATE_READY);
			break;
		}

		index = vpn_provider_get_index(provider);
		vpn_provider_ref(provider);
		data->watch = vpn_rtnl_add_newlink_watch(index,
						     vpn_newlink, provider);
		err = connman_inet_ifup(index);
		if (err < 0) {
			if (err == -EALREADY)
				/*
				 * So the interface is up already, that is just
				 * great. Unfortunately in this case the
				 * newlink watch might not have been called at
				 * all. We must manually call it here so that
				 * the provider can go to ready state and the
				 * routes are setup properly.
				 */
				vpn_newlink(IFF_UP, 0, provider);
			else
				DBG("Cannot take interface %d up err %d/%s",
					index, -err, strerror(-err));
		}
		break;

	case VPN_STATE_UNKNOWN:
	case VPN_STATE_IDLE:
	case VPN_STATE_DISCONNECT:
	case VPN_STATE_FAILURE:
		vpn_provider_set_state(provider,
					VPN_PROVIDER_STATE_DISCONNECT);
		break;

	case VPN_STATE_AUTH_FAILURE:
		vpn_provider_indicate_error(provider,
					VPN_PROVIDER_ERROR_AUTH_FAILED);
		break;
	}

	return NULL;
}