Exemple #1
0
/**
 * Read data from the message buffer we just received.
 *
 * @return TRUE whilst we think there is more data to read in the buffer.
 */
static gboolean
browse_data_read(struct browse_ctx *bc, pmsg_t *mb)
{
	/*
	 * Read header if it has not been fully fetched yet.
	 */

	if (!bc->has_header) {
		char *w = cast_to_gpointer(&bc->header);

		g_assert(sizeof bc->header >= bc->pos);
		bc->pos += pmsg_read(mb, &w[bc->pos], sizeof bc->header - bc->pos);
		if (bc->pos < sizeof bc->header)
			return FALSE;

		bc->has_header = TRUE;		/* We have read the full header */

		bc->size = gnutella_header_get_size(&bc->header);

		/*
		 * Protect against too large data.
		 */

		if (bc->size > BH_DL_MAX_SIZE) {
			download_stop(bc->owner, GTA_DL_ERROR, "Gnutella payload too big");
			return FALSE;
		}

		/*
		 * Resize payload buffer if needed
		 */

		if (bc->size > bc->data_size) {
			bc->data_size = MAX(BH_DL_DEFAULT_SIZE, bc->size);
			bc->data = hrealloc(bc->data, bc->data_size);
		}

		bc->pos = 0;

		/* FALL THROUGH */
	}

	/*
	 * Read message data, if any.
	 */

	if (bc->size) {
		g_assert(bc->size >= bc->pos);
		bc->pos += pmsg_read(mb, &bc->data[bc->pos], bc->size - bc->pos);
	}

	if (bc->pos >= bc->size) {
		bc->has_header = FALSE;		/* For next message */
		bc->pos = 0;
		return TRUE; /* Must process message and continue */
	} else {
		return FALSE;
	}
}
Exemple #2
0
/**
 * Identify the traffic type received on the UDP socket.
 *
 * This routine uses simple heuristics that ensure we're properly discriminating
 * incoming traffic on the UDP socket between regular Gnutella traffic and
 * semi-reliable UDP traffic (which adds a small header before its actual
 * payload).
 *
 * Most messages will be un-ambiguous, and the probabilty of misclassifying
 * an ambiguous message (one that look like valid for both types, based on
 * header inspections) is brought down to less than 1 in a billion, making
 * it perfectly safe in practice.
 *
 * @return intuited type
 */
static enum udp_traffic
udp_intuit_traffic_type(const gnutella_socket_t *s,
	const void *data, size_t len)
{
	enum udp_traffic utp;

	utp = udp_check_semi_reliable(data, len);

	if (len >= GTA_HEADER_SIZE) {
		uint16 size;			/* Payload size, from the Gnutella message */
		gmsg_valid_t valid;

		valid = gmsg_size_valid(data, &size);

		switch (valid) {
		case GMSG_VALID:
		case GMSG_VALID_MARKED:
			if ((size_t) size + GTA_HEADER_SIZE == len) {
				uint8 function, hops, ttl;

				function = gnutella_header_get_function(data);

				/*
				 * If the header cannot be that of a known semi-reliable
				 * UDP protocol, there is no ambiguity.
				 */

				if (UNKNOWN == utp) {
					return GTA_MSG_DHT == function ?
						DHT : GTA_MSG_RUDP == function ?
						RUDP : GNUTELLA;
				}

				/*
				 * Message is ambiguous: its leading header appears to be
				 * both a legitimate Gnutella message and a semi-reliable UDP
				 * header.
				 *
				 * We have to apply some heuristics to decide whether to handle
				 * the message as a Gnutella one or as a semi-reliable UDP one,
				 * knowing that if we improperly classify it, the message will
				 * not be handled correctly.
				 *
				 * Note that this is highly unlikely.  There is about 1 chance
				 * in 10 millions (1 / 2^23 exactly) to mis-interpret a random
				 * Gnutella MUID as the start of one of the semi-reliable
				 * protocols we support.  Our discriminating logic probes a
				 * few more bytes (say 2 at least) which are going to let us
				 * decide with about 99% certainety.  So mis-classification
				 * will occur only once per billion -- a ratio which is OK.
				 *
				 * We could also mistakenely handle a semi-reliable UDP message
				 * as a Gnutella one.  For that to happen, the payload must
				 * contain a field that will be exactly the message size,
				 * a 1 / 2^32 event (since the size is 4 bytes in Gnutella).
				 * However, if message flags are put to use for Gnutella UDP,
				 * this ratio could lower to 1 / 2^16 and that is too large
				 * a chance (about 1.5 in 100,000).
				 *
				 * So when we think an ambiguous message could be a valid
				 * Gnutella message, we also check whether the message could
				 * not be interpreted as a valid semi-reliable UDP one, and
				 * we give priority to that classification if we have a match:
				 * correct sequence number, consistent count and emitting host.
				 * This checks roughly 3 more bytes in the message, yielding
				 * a misclassification for about 1 / 2^(16+24) random cases.
				 */

				hops = gnutella_header_get_hops(data);
				ttl = gnutella_header_get_ttl(data);

				gnet_stats_inc_general(GNR_UDP_AMBIGUOUS);

				if (GNET_PROPERTY(udp_debug)) {
					g_debug("UDP ambiguous datagram from %s: "
						"%zu bytes (%u-byte payload), "
						"function=%u, hops=%u, TTL=%u, size=%u",
						host_addr_port_to_string(s->addr, s->port),
						len, size, function, hops, ttl,
						gnutella_header_get_size(data));
					dump_hex(stderr, "UDP ambiguous datagram", data, len);
				}

				switch (function) {
				case GTA_MSG_DHT:
					/*
					 * A DHT message must be larger than KDA_HEADER_SIZE bytes.
					 */

					if (len < KDA_HEADER_SIZE)
						break;		/* Not a DHT message */

					/*
					 * DHT messages have no bits defined in the size field
					 * to mark them.
					 */

					if (valid != GMSG_VALID)
						break;		/* Higest bit set, not a DHT message */

					/*
					 * If it is a DHT message, it must have a valid opcode.
					 */

					function = kademlia_header_get_function(data);

					if (function > KDA_MSG_MAX_ID)
						break;		/* Not a valid DHT opcode */

					/*
					 * Check the contact address length: it must be 4 in the
					 * header, because there is only room for an IPv4 address.
					 */

					if (!kademlia_header_constants_ok(data))
						break;		/* Not a valid Kademlia header */

					/*
					 * Make sure we're not mistaking a valid semi-reliable UDP
					 * message as a DHT message.
					 */

					if (udp_is_valid_semi_reliable(utp, s, data, len))
						break;		/* Validated it as semi-reliable UDP */

					g_warning("UDP ambiguous message from %s (%zu bytes total),"
						" DHT function is %s",
						host_addr_port_to_string(s->addr, s->port),
						len, kmsg_name(function));

					return DHT;

				case GTA_MSG_INIT:
				case GTA_MSG_PUSH_REQUEST:
				case GTA_MSG_SEARCH:
					/*
					 * No incoming messages of this type can have a TTL
					 * indicating a deflated payload, since there is no
					 * guarantee the host would be able to read it (deflated
					 * UDP is negotiated and can therefore only come from a
					 * response).
					 */

					if (ttl & GTA_UDP_DEFLATED)
						break;			/* Not Gnutella, we're positive */

					/* FALL THROUGH */

				case GTA_MSG_INIT_RESPONSE:
				case GTA_MSG_VENDOR:
				case GTA_MSG_SEARCH_RESULTS:
					/*
					 * To further discriminate, look at the hop count.
					 * Over UDP, the hop count will be low (0 or 1 mostly)
					 * and definitely less than 3 since the only UDP-relayed
					 * messages are from GUESS, and they can travel at most
					 * through a leaf and an ultra node before reaching us.
					 */

					if (hops >= 3U)
						break;			/* Gnutella is very unlikely */

					/*
					 * Check the TTL, cleared from bits that indicate
					 * support for deflated UDP or a deflated payload.
					 * No servent should send a TTL greater than 7, which
					 * was the de-facto limit in the early Gnutella days.
					 */

					if ((ttl & ~(GTA_UDP_CAN_INFLATE | GTA_UDP_DEFLATED)) > 7U)
						break;			/* Gnutella is very unlikely */

					/*
					 * Make sure we're not mistaking a valid semi-reliable UDP
					 * message as a Gnutella message.
					 */

					if (udp_is_valid_semi_reliable(utp, s, data, len))
						break;		/* Validated it as semi-reliable UDP */

					g_warning("UDP ambiguous message from %s (%zu bytes total),"
						" Gnutella function is %s, hops=%u, TTL=%u",
						host_addr_port_to_string(s->addr, s->port),
						len, gmsg_name(function), hops, ttl);

					return GNUTELLA;

				case GTA_MSG_RUDP:
					/*
					 * RUDP traffic is special: the only meaningful fields
					 * of the Gnutella header are the opcode field (which we
					 * have read here since we fall into this case) and the
					 * Gnutella header size.
					 *
					 * The TTL and hops fields cannot be interpreted to
					 * disambiguate, so our only option is deeper inspection.
					 */

					if (udp_is_valid_semi_reliable(utp, s, data, len))
						break;		/* Validated it as semi-reliable UDP */

					g_warning("UDP ambiguous message from %s (%zu bytes total),"
						" interpreted as RUDP packet",
						host_addr_port_to_string(s->addr, s->port), len);

					return RUDP;
					
				case GTA_MSG_STANDARD:	/* Nobody is using this function code */
				default:
					break;				/* Not a function we expect over UDP */
				}

				/*
				 * Will be handled as semi-reliable UDP.
				 */

				gnet_stats_inc_general(GNR_UDP_AMBIGUOUS_AS_SEMI_RELIABLE);

				{
					udp_tag_t tag;

					memcpy(tag.value, data, sizeof tag.value);

					g_warning("UDP ambiguous message (%zu bytes total), "
						"not Gnutella (function is %d, hops=%u, TTL=%u) "
						"handling as semi-reliable UDP (tag=\"%s\")",
						len, function, hops, ttl, udp_tag_to_string(tag));
				}
				return utp;
			}
			/* FALL THROUGH */
		case GMSG_VALID_NO_PROCESS:
		case GMSG_INVALID:
			break;
		}
	}

	return utp;
}