Пример #1
0
/*
 * Torsocks call for connect(2).
 */
LIBC_CONNECT_RET_TYPE tsocks_connect(LIBC_CONNECT_SIG)
{
	int ret, ret_errno;
	struct connection *new_conn;
	struct onion_entry *on_entry;

	DBG("Connect caught on fd %d", sockfd);

	/*
	 * Validate socket values in order to see if we can handle this connect
	 * through Tor.
	 */
	ret = tsocks_validate_socket(sockfd, addr);
	if (ret == 1) {
		/* Tor can't handle it so send it to the libc. */
		goto libc_connect;
	} else if (ret == -1) {
		/* Validation failed. Stop right now. */
		goto error;
	}
	/* Implicit else statement meaning we continue processing the connect. */
	assert(!ret);

	/*
	 * Lock registry to get the connection reference if one. In this code path,
	 * if a connection object is found, it will not be used since a double
	 * connect() on the same file descriptor is an error so the registry is
	 * quickly unlocked and no reference is needed.
	 */
	connection_registry_lock();
	new_conn = connection_find(sockfd);
	connection_registry_unlock();
	if (new_conn) {
		/* Double connect() for the same fd. */
		errno = EISCONN;
		goto error;
	}

	/*
	 * See if the IP being connected is an onion IP cookie mapping to an
	 * existing .onion address.
	 */
	onion_pool_lock(&tsocks_onion_pool);
	on_entry = onion_entry_find_by_addr(addr, &tsocks_onion_pool);
	onion_pool_unlock(&tsocks_onion_pool);
	if (on_entry) {
		/*
		 * Create a connection with the onion IP cookie since getpeername()
		 * might need it, and set connection domain and hostname to use
		 * the onion address name found before.
		 */
		new_conn = connection_create(sockfd, addr);
		if (!new_conn) {
			errno = ENOMEM;
			goto error;
		}
		new_conn->dest_addr.domain = CONNECTION_DOMAIN_NAME;
		new_conn->dest_addr.hostname.port = utils_get_port_from_addr(addr);
		new_conn->dest_addr.hostname.addr = strdup(on_entry->hostname);
		if (!new_conn->dest_addr.hostname.addr) {
			ret_errno = ENOMEM;
			goto error_free;
		}
	} else {
		/*
		 * Check if address is localhost. At this point, we are sure it's not a
		 * .onion cookie address that is by default in the loopback network
		 * thus this check is done after the onion entry lookup.
		 */
		if (utils_sockaddr_is_localhost(addr)) {
			/*
			 * Certain setups need to be able to reach localhost, despite
			 * running torsocks. If they enabled the config option, allow such
			 * connections.
			 */
			if (tsocks_config.allow_outbound_localhost) {
				goto libc_connect;
			}

			WARN("[connect] Connection to a local address are denied since it "
					"might be a TCP DNS query to a local DNS server. "
					"Rejecting it for safety reasons.");
			errno = EPERM;
			goto error;
		}

		new_conn = connection_create(sockfd, addr);
		if (!new_conn) {
			errno = ENOMEM;
			goto error;
		}
	}

	/* Connect the socket to the Tor network. */
	ret = tsocks_connect_to_tor(new_conn);
	if (ret < 0) {
		ret_errno = -ret;
		goto error_free;
	}

	connection_registry_lock();
	/* This can't fail since a lookup was done previously. */
	connection_insert(new_conn);
	connection_registry_unlock();

	/* Flag errno for success */
	ret = errno = 0;
	return ret;

libc_connect:
	return tsocks_libc_connect(LIBC_CONNECT_ARGS);

error_free:
	/*
	 * Put back reference of newly created connection. Will be freed if
	 * refcount goes down to 0.
	 */
	connection_put_ref(new_conn);
	errno = ret_errno;
error:
	/* At this point, errno MUST be set to a valid connect() error value. */
	return -1;
}
Пример #2
0
/*
 * Torsocks call for connect(2).
 */
LIBC_CONNECT_RET_TYPE tsocks_connect(LIBC_CONNECT_SIG)
{
	int ret, sock_type;
	socklen_t optlen;
	struct connection *new_conn;
	struct onion_entry *on_entry;
	struct sockaddr_in *inet_addr;

	DBG("Connect catched on fd %d", __sockfd);

	optlen = sizeof(sock_type);
	ret = getsockopt(__sockfd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen);
	if (ret < 0) {
		/* Use the getsockopt() errno value. */
		goto error;
	}

	/* We can't handle a non inet socket. */
	if (__addr->sa_family != AF_INET &&
			__addr->sa_family != AF_INET6) {
		DBG("[conect] Connection is not IPv4/v6. Ignoring.");
		goto libc_connect;
	}

	/*
	 * Refuse non stream socket. There is a chance that this might be a DNS
	 * request that we can't pass through Tor using raw UDP packet.
	 */
	if (sock_type != SOCK_STREAM) {
		WARN("[connect] UDP or ICMP stream can't be handled. Rejecting.");
		errno = EBADF;
		goto error;
	}

	DBG("[connect] Socket family %s and type %d",
			__addr->sa_family == AF_INET ? "AF_INET" : "AF_INET6", sock_type);

	inet_addr = (struct sockaddr_in *) __addr;

	/*
	 * Lock registry to get the connection reference if one. In this code path,
	 * if a connection object is found, it will not be used since a double
	 * connect() on the same file descriptor is an error so the registry is
	 * quickly unlocked and no reference is needed.
	 */
	connection_registry_lock();
	new_conn = connection_find(__sockfd);
	connection_registry_unlock();
	if (new_conn) {
		/* Double connect() for the same fd. */
		errno = EISCONN;
		goto error;
	}

	/*
	 * See if the IP being connected is an onion IP cookie mapping to an
	 * existing .onion address.
	 */
	onion_pool_lock(&tsocks_onion_pool);
	on_entry = onion_entry_find_by_ip(inet_addr->sin_addr.s_addr,
			&tsocks_onion_pool);
	onion_pool_unlock(&tsocks_onion_pool);
	if (on_entry) {
		/*
		 * Create a connection without a destination address since we will set
		 * the onion address name found before.
		 */
		new_conn = connection_create(__sockfd, NULL);
		if (!new_conn) {
			errno = ENOMEM;
			goto error;
		}
		new_conn->dest_addr.domain = CONNECTION_DOMAIN_NAME;
		new_conn->dest_addr.hostname.addr = strdup(on_entry->hostname);
		new_conn->dest_addr.hostname.port = inet_addr->sin_port;
	} else {
		/*
		 * Check if address is local IPv4. At this point, we are sure it's not
		 * a .onion cookie address that is by default in the loopback network.
		 */
		if (__addr->sa_family == AF_INET &&
				utils_is_ipv4_local(inet_addr->sin_addr.s_addr)) {
			WARN("[connect] Connection to a local address are denied since it "
					"might be a TCP DNS query to a local DNS server. "
					"Rejecting it for safety reasons.");
			errno = EPERM;
			goto error;
		}

		new_conn = connection_create(__sockfd, __addr);
		if (!new_conn) {
			errno = ENOMEM;
			goto error;
		}
	}

	/* Connect the socket to the Tor network. */
	ret = tsocks_connect_to_tor(new_conn);
	if (ret < 0) {
		errno = -ret;
		goto error;
	}

	connection_registry_lock();
	/* This can't fail since a lookup was done previously. */
	connection_insert(new_conn);
	connection_registry_unlock();

	/* Flag errno for success */
	ret = errno = 0;
	return ret;

libc_connect:
	return tsocks_libc_connect(LIBC_CONNECT_ARGS);
error:
	/* At this point, errno MUST be set to a valid connect() error value. */
	return -1;
}