Пример #1
0
/**
 * Select proper RX layer for semi-reliable UDP traffic.
 *
 * Source address is checked for hostile hosts in order to enforce a
 * total blackout.
 *
 * @param utp		UDP traffic type
 * @param from		source address
 * @param len		length of message, for logging only
 *
 * @return the RX layer if found, NULL if none or the address is hostile.
 */
static rxdrv_t *
udp_get_rx_semi_reliable(enum udp_traffic utp, host_addr_t from, size_t len)
{
	unsigned i = 0;

	if (hostiles_is_bad(from)) {
		if (GNET_PROPERTY(udp_debug)) {
			hostiles_flags_t flags = hostiles_check(from);
			g_warning("UDP got %s (%zu bytes) from hostile %s (%s) -- dropped",
				udp_traffic_to_string(utp), len, host_addr_to_string(from),
				hostiles_flags_to_string(flags));
		}
		gnet_stats_inc_general(GNR_UDP_SR_RX_FROM_HOSTILE_IP);
		return NULL;		/* Ignore message */
	}

	switch (host_addr_net(from)) {
	case NET_TYPE_IPV4:		i = 0; break;
	case NET_TYPE_IPV6:		i = 1; break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		g_assert_not_reached();
	}

	return
		SEMI_RELIABLE_GTA == utp ? rx_sr_gta[i] :
		SEMI_RELIABLE_GND == utp ? rx_sr_gnd[i] :
		NULL;
}
Пример #2
0
/**
 * Notification from the socket layer that we got a new datagram.
 *
 * @param s				the receiving socket (with s->addr and s->port set)
 * @param data			start of received data (not necessarily s->buf)
 * @param len			length of received data (not necessarily s->pos)
 * @param truncated		whether received datagram was truncated
 *
 * If `truncated' is true, then the message was too large for the
 * socket buffer.
 */
void
udp_received(const gnutella_socket_t *s,
	const void *data, size_t len, bool truncated)
{
	gnutella_node_t *n;
	bool bogus = FALSE, dht = FALSE, rudp = FALSE, g2 = FALSE;
	hostiles_flags_t hflags;

	/*
	 * This must be regular Gnutella / DHT traffic.
	 */

	inet_udp_got_incoming(s->addr);

	/*
	 * We need to identify semi-reliable UDP traffic early, because that
	 * traffic needs to go through the RX stack to reassemble the final
	 * payload out of the many fragments, or to process the acknowledgments.
	 *
	 * We have to apply heuristics however because the leading 8 bytes could
	 * be just a part of gnutella message (the first 8 bytes of a GUID).
	 * One thing is certain though: if the size is less than that of a a
	 * Gnutella header, it has to be semi-reliable UDP traffic...
	 *
	 * Because semi-reliable UDP uses small payloads, much smaller than our
	 * socket buffer, the datagram cannot be truncated.
	 */

	if (!truncated) {
		enum udp_traffic utp;
		rxdrv_t *rx;

		utp = udp_intuit_traffic_type(s, data, len);

		switch (utp) {
		case GNUTELLA:
			goto unreliable;
		case RUDP:
			rudp = TRUE;
			gnet_stats_count_general(GNR_RUDP_RX_BYTES, len);
			goto rudp;		/* Don't account this message in UDP statistics */
		case DHT:
			dht = TRUE;
			goto unreliable;
		case UNKNOWN:
			goto unknown;
		case SEMI_RELIABLE_GTA:
			break;
		case SEMI_RELIABLE_GND:
			if (!node_g2_active())
				return;		/* Blackout, ignore datagram if G2 was disabled */
			g2 = TRUE;
			break;
		}

		/*
		 * We are going to treat this message a a semi-reliable UDP fragment.
		 *
		 * Account the size of the payload for traffic purposes, then redirect
		 * the message to the RX layer that reassembles and dispatches these
		 * messages.
		 */

		bws_udp_count_read(len, FALSE);	/* We know it's not DHT traffic */

		rx = udp_get_rx_semi_reliable(utp, s->addr, len);

		if (rx != NULL) {
			gnet_host_t from;

			gnet_host_set(&from, s->addr, s->port);
			ut_got_message(rx, data, len, &from);
		}

		return;
	}

unknown:
	/*
	 * Discriminate between Gnutella UDP and DHT messages, so that we
	 * can account received data with the proper bandwidth scheduler.
	 */

	if (len >= GTA_HEADER_SIZE)
		dht = GTA_MSG_DHT == gnutella_header_get_function(data);

	/* FALL THROUGH */

unreliable:
	/*
	 * Account for Gnutella / DHT incoming UDP traffic.
	 */

	bws_udp_count_read(len, dht);

	/* FALL THROUGH */

rudp:
	/*
	 * The RUDP layer is used to implement firewalled-to-firewalled transfers
	 * via a mini TCP-like layer built on top of UDP.  Therefore, it is used
	 * as the basis for higher-level connections (HTTP) and will have to be
	 * accounted for once the type of traffic is known, by upper layers, as
	 * part of the upload/download traffic.
	 *
	 * Of course, the higher levels will never see all the bytes that pass
	 * through, such as acknowledgments or retransmissions, but that is also
	 * the case for TCP-based sockets.
	 *		--RAM, 2012-11-02.
	 */

	g_assert(!g2);	/* All G2 UDP traffic comes via the semi-reliable layer */

	/*
	 * If we get traffic from a bogus IP (unroutable), warn, for now.
	 */

	if (bogons_check(s->addr)) {
		bogus = TRUE;

		if (GNET_PROPERTY(udp_debug)) {
			g_warning("UDP %sdatagram (%zu byte%s) received from bogus IP %s",
				truncated ? "truncated " : "",
				len, plural(len),
				host_addr_to_string(s->addr));
		}
		gnet_stats_inc_general(GNR_UDP_BOGUS_SOURCE_IP);
	}

	/*
	 * Traffic from hosts sending gibberish data or information we previously
	 * determined as being invalid / suspicious are simply discarded to avoid
	 * further processing (which would probably lead to them being further
	 * discarded as invalid, unparseable, etc...).
	 *
	 * We let statically-banned hosts through though so that we may parse
	 * their message and log dropping in upper layers, for statistics per
	 * message type.  We only drop known gibberish at this level.
	 */

	hflags = hostiles_check(s->addr);

	if (hflags & HSTL_GIBBERISH) {
		if (GNET_PROPERTY(udp_debug)) {
			g_warning("UDP %sdatagram (%zu byte%s) received from "
				"shunned IP %s (%s) -- dropped",
				truncated ? "truncated " : "",
				len, plural(len),
				host_addr_to_string(s->addr), hostiles_flags_to_string(hflags));
		}
		gnet_stats_inc_general(GNR_UDP_SHUNNED_SOURCE_IP);
		return;
	}

	/*
	 * Get proper pseudo-node.
	 *
	 * These routines can return NULL if the address/port combination is
	 * not correct, but this will be handled by udp_is_valid_gnet().
	 */

	n = dht ? node_dht_get_addr_port(s->addr, s->port) :
		node_udp_get_addr_port(s->addr, s->port);

	if (!udp_is_valid_gnet(n, s, truncated, data, len))
		return;

	/*
	 * RUDP traffic does not go to the upper Gnutella processing layers.
	 */

	if (rudp) {
		/* Not ready for prime time */
#if 0
		rudp_handle_packet(s->addr, s->port. data, len);
#endif
		return;
	}

	/*
	 * Process message as if it had been received from regular Gnet by
	 * another node, only we'll use a special "pseudo UDP node" as origin.
	 */

	if (GNET_PROPERTY(udp_debug) > 19 || (bogus && GNET_PROPERTY(udp_debug)))
		g_debug("UDP got %s from %s%s", gmsg_infostr_full(data, len),
			bogus ? "BOGUS " : "", host_addr_port_to_string(s->addr, s->port));

	node_udp_process(n, s, data, len);
}