Esempio n. 1
0
/**
 * Resolves an IP address to a hostname per DNS.
 *
 * @param ha	The host address to resolve.
 * @return		On success, the hostname is returned. Otherwise, NULL is
 *				returned. The resulting string points to a static buffer.
 */
const char *
host_addr_to_name(host_addr_t addr)
{
	socket_addr_t sa;

	if (host_addr_can_convert(addr, NET_TYPE_IPV4)) {
		(void) host_addr_convert(addr, &addr, NET_TYPE_IPV4);
	}
	if (0 == socket_addr_set(&sa, addr, 0)) {
		return NULL;
	}

#ifdef HAS_GETNAMEINFO
	{
		static char host[1025];
		int error;

		error = getnameinfo(socket_addr_get_const_sockaddr(&sa),
					socket_addr_get_len(&sa), host, sizeof host, NULL, 0, 0);
		if (error) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			g_message("getnameinfo() failed for \"%s\": %s",
				buf, gai_strerror(error));
			return NULL;
		}
		return host;
	}
#else	/* !HAS_GETNAMEINFO */
	{
		const struct hostent *he;
		socklen_t len = 0;
		const char *ptr = NULL;

		switch (host_addr_net(addr)) {
		case NET_TYPE_IPV4:
			ptr = cast_to_gchar_ptr(&sa.inet4.sin_addr);
			len = sizeof sa.inet4.sin_addr;
			break;
		case NET_TYPE_IPV6:
#ifdef HAS_IPV6
			ptr = cast_to_gchar_ptr(&sa.inet6.sin6_addr);
			len = sizeof sa.inet6.sin6_addr;
			break;
#endif /* HAS_IPV6 */
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			return NULL;
		}
		g_return_val_if_fail(ptr, NULL);
		g_return_val_if_fail(0 != len, NULL);

		he = gethostbyaddr(ptr, len, socket_addr_get_family(&sa));
		if (!he) {
			char buf[HOST_ADDR_BUFLEN];

			host_addr_to_string_buf(addr, buf, sizeof buf);
			gethostbyname_error(buf);
			return NULL;
		}
		return he->h_name;
	}
#endif	/* HAS_GETNAMEINFO */
}
Esempio n. 2
0
/**
 * Create a security token from host address and port using specified key.
 *
 * Optionally, extra contextual data may be given (i.e. the token is not
 * only based on the address and port) to make the token more unique to
 * a specific context.
 *
 * @param stg		the security token generator
 * @param n			key index to use
 * @param tok		where security token is written
 * @param addr		address of the host for which we're generating a token
 * @param port		port of the host for which we're generating a token
 * @param data		optional contextual data
 * @param len		length of contextual data
 */
static void
sectoken_generate_n(sectoken_gen_t *stg, size_t n,
	sectoken_t *tok, host_addr_t addr, uint16 port,
	const void *data, size_t len)
{
	char block[8];
	char enc[8];
	char *p = block;

	sectoken_gen_check(stg);
	g_assert(tok != NULL);
	g_assert(size_is_non_negative(n));
	g_assert(n < stg->keycnt);
	g_assert((NULL != data) == (len != 0));

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		p = poke_be32(p, host_addr_ipv4(addr));
		break;
	case NET_TYPE_IPV6:
		{
			uint val;

			val = binary_hash(host_addr_ipv6(&addr), 16);
			p = poke_be32(p, val);
		}
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		g_error("unexpected address for security token generation: %s",
			host_addr_to_string(addr));
	}

	p = poke_be16(p, port);
	p = poke_be16(p, 0);		/* Filler */

	g_assert(p == &block[8]);

	STATIC_ASSERT(sizeof(tok->v) == sizeof(uint32));
	STATIC_ASSERT(sizeof(block) == sizeof(enc));

	tea_encrypt(&stg->keys[n], enc, block, sizeof block);

	/*
	 * If they gave contextual data, encrypt them by block of 8 bytes,
	 * filling the last partial block with zeroes if needed.
	 */

	if (data != NULL) {
		const void *q = data;
		size_t remain = len;
		char denc[8];

		STATIC_ASSERT(sizeof(denc) == sizeof(enc));

		while (remain != 0) {
			size_t fill = MIN(remain, 8U);
			unsigned i;

			if (fill != 8U)
				ZERO(&block);

			memcpy(block, q, fill);
			remain -= fill;
			q = const_ptr_add_offset(q, fill);

			/*
			 * Encrypt block of contextual data (possibly filled with trailing
			 * zeroes) and merge back the result into the main encryption
			 * output with XOR.
			 */

			tea_encrypt(&stg->keys[n], denc, block, sizeof block);

			for (i = 0; i < sizeof denc; i++)
				enc[i] ^= denc[i];
		}
	}

	poke_be32(tok->v, tea_squeeze(enc, sizeof enc));
}
Esempio n. 3
0
/**
 * Initiate an UDP RPC transaction.
 *
 * The message held in ``data'' is sent to the specified address and port.
 * Upon reception of a reply from that host, the callback is invoked.
 * If no reply is received after some time, the callaback is also invoked.
 *
 * @param what		type of RPC, for logging (static string)
 * @param addr		address where RPC should be sent to
 * @param port		port where RPC should be sent to
 * @param data		message data to send
 * @param len		length of data to send
 * @param timeout	timeout in milliseconds to get a reply
 * @param cb		callback to invoke on reply or timeout
 * @param arg		additionnal callback argument
 *
 * @return 0 if OK, -1 if we could not initiate the RPC, with errno set.
 */
int
urpc_send(const char *what,
	host_addr_t addr, uint16 port, const void *data, size_t len,
	unsigned long timeout, urpc_cb_t cb, void *arg)
{
	struct urpc_cb *ucb;
	struct gnutella_socket *s;
	host_addr_t bind_addr = zero_host_addr;
	gnet_host_t to;
	ssize_t r;

	/*
	 * Create anonymous socket to send/receive the RPC.
	 */

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		bind_addr = ipv4_unspecified;
		break;
	case NET_TYPE_IPV6:
		bind_addr = ipv6_unspecified;
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		g_assert_not_reached();
	}

	s = socket_udp_listen(bind_addr, 0, urpc_received);
	if (NULL == s) {
		if (GNET_PROPERTY(udp_debug)) {
			g_warning("unable to create anonymous UDP %s socket for %s RPC: %m",
				net_type_to_string(host_addr_net(bind_addr)), what);
		}
		return -1;
	}

	/*
	 * Send the message.
	 */

	gnet_host_set(&to, addr, port);
	r = (s->wio.sendto)(&s->wio, &to, data, len);

	/*
	 * Reset errno if there was no "real" error to prevent getting a
	 * bogus and possibly misleading error message later.
	 */

	if ((ssize_t) -1 == r) {
		if (GNET_PROPERTY(udp_debug)) {
			g_warning("unable to send UDP %s RPC to %s: %m",
				what, host_addr_port_to_string(addr, port));
		}
	} else {
		errno = 0;
	}

	if (len != UNSIGNED(r)) {
		if ((ssize_t) -1 != r) {
			if (GNET_PROPERTY(udp_debug)) {
				g_warning("unable to send whole %zu-byte UDP %s RPC to %s: "
					"only sent %zu byte%s",
					len, what, host_addr_port_to_string(addr, port),
					r, 1 == r ? "" : "s");
			}
		}
		socket_free_null(&s);
		errno = EIO;
		return -1;
	}

	/*
	 * Make sure socket_udp_event() will only process replies one at a time
	 * since we're going to close the anonymous UDP socket as soon as we
	 * get a reply.
	 */

	socket_set_single(s, TRUE);

	/*
	 * Message was sent, wait for the answer.
	 */

	WALLOC(ucb);
	ucb->magic = URPC_CB_MAGIC;
	ucb->addr = addr;
	ucb->port = port;
	ucb->s = s;
	ucb->cb = cb;
	ucb->arg = arg;
	ucb->timeout_ev = cq_main_insert(timeout, urpc_timed_out, ucb);
	ucb->what = what;

	htable_insert(pending, s, ucb);

	return 0;
}