コード例 #1
0
ファイル: node.c プロジェクト: graaff/gtk-gnutella
/**
 * Handle message coming from G2 node.
 */
void
g2_node_handle(gnutella_node_t *n)
{
	g2_tree_t *t;
	size_t plen;
	enum g2_msg type;

	node_check(n);
	g_assert(NODE_TALKS_G2(n));

	t = g2_frame_deserialize(n->data, n->size, &plen, FALSE);
	if (NULL == t) {
		if (GNET_PROPERTY(g2_debug) > 0 || GNET_PROPERTY(log_bad_g2)) {
			g_warning("%s(): cannot deserialize /%s from %s",
				G_STRFUNC, g2_msg_raw_name(n->data, n->size), node_infostr(n));
		}
		if (GNET_PROPERTY(log_bad_g2))
			dump_hex(stderr, "G2 Packet", n->data, n->size);
		return;
	} else if (plen != n->size) {
		if (GNET_PROPERTY(g2_debug) > 0 || GNET_PROPERTY(log_bad_g2)) {
			g_warning("%s(): consumed %zu bytes but /%s from %s had %u",
				G_STRFUNC, plen, g2_msg_raw_name(n->data, n->size),
				node_infostr(n), n->size);
		}
		if (GNET_PROPERTY(log_bad_g2))
			dump_hex(stderr, "G2 Packet", n->data, n->size);
		hostiles_dynamic_add(n->addr,
			"cannot parse incoming messages", HSTL_GIBBERISH);
		goto done;
	} else if (GNET_PROPERTY(g2_debug) > 19) {
		g_debug("%s(): received packet from %s", G_STRFUNC, node_infostr(n));
		g2_tfmt_tree_dump(t, stderr, G2FMT_O_PAYLEN);
	}

	type = g2_msg_name_type(g2_tree_name(t));

	switch (type) {
	case G2_MSG_PI:
		g2_node_handle_ping(n, t);
		break;
	case G2_MSG_PO:
		g2_node_handle_pong(n, t);
		break;
	case G2_MSG_LNI:
		g2_node_handle_lni(n, t);
		break;
	case G2_MSG_KHL:
		g2_node_handle_khl(t);
		break;
	case G2_MSG_PUSH:
		handle_push_request(n, t);
		break;
	case G2_MSG_Q2:
		g2_node_handle_q2(n, t);
		break;
	case G2_MSG_QA:
	case G2_MSG_QKA:
		g2_node_handle_rpc_answer(n, t, type);
		break;
	case G2_MSG_QH2:
		search_g2_results(n, t);
		break;
	default:
		g2_node_drop(G_STRFUNC, n, t, "default");
		break;
	}

done:
	g2_tree_free_null(&t);
}
コード例 #2
0
ファイル: udp.c プロジェクト: Longdengyu/gtk-gnutella
/**
 * Look whether the datagram we received is a valid Gnutella packet.
 *
 * The routine also handles traffic statistics (reception and dropping).
 *
 * If ``n'' is not NULL, then ``s'' may be NULL.  If ``n'' is NULL, then
 * ``s'' must not be NULL.
 *
 * @param n				the pseudo UDP reception node (NULL if invalid IP:port)
 * @param s				the socket on which we got the UDP datagram
 * @param truncated		whether datagram was truncated during reception
 * @param header		header of message
 * @param payload		payload of message (maybe not contiguous with header)
 * @param len			total length of message (header + payload)
 *
 * @return TRUE if valid, FALSE otherwise.
 */
bool
udp_is_valid_gnet_split(gnutella_node_t *n, const gnutella_socket_t *s,
	bool truncated, const void *header, const void *payload, size_t len)
{
	const char *msg;
	uint16 size;			/**< Payload size, from the Gnutella message */

	g_assert(s != NULL || n != NULL);

	/*
	 * If we can't get a proper UDP node for this address/port combination,
	 * ignore the message.
	 */

	if (NULL == n) {
		msg = "Invalid address/port combination";
		goto not;
	}

	if (len < GTA_HEADER_SIZE) {
		msg = "Too short";
		goto not;
	}

	/*
	 * We have enough to account for packet reception.
	 * Note that packet could be garbage at this point.
	 */

	memcpy(n->header, header, sizeof n->header);
	n->size = len - GTA_HEADER_SIZE;		/* Payload size if Gnutella msg */

	gnet_stats_count_received_header(n);
	gnet_stats_count_received_payload(n, payload);

	/*
	 * If the message was truncated, then there is also going to be a
	 * size mismatch, but we want to flag truncated messages as being
	 * "too large" because this is mainly why we reject them.  They may
	 * be legitimate Gnutella packets, too bad.
	 */

	if (truncated) {
		msg = "Truncated (too large?)";
		goto too_large;
	}

	/*
	 * Message sizes are architecturally limited to 64K bytes.
	 *
	 * We don't ensure the leading bits are zero in the size field because
	 * this constraint we put allows us to use those bits for flags in
	 * future extensions.
	 *
	 * The downside is that we have only 3 bytes (2 bytes for the size and
	 * 1 byte for the function type) to identify a valid Gnutella packet.
	 */

	switch (gmsg_size_valid(header, &size)) {
	case GMSG_VALID:
	case GMSG_VALID_MARKED:
		break;
	case GMSG_VALID_NO_PROCESS:
		hostiles_dynamic_add(n->addr,
			"improper Gnutella header", HSTL_GIBBERISH);
		msg = "Header flags undefined for now";
		goto drop;
	case GMSG_INVALID:
		hostiles_dynamic_add(n->addr,
			"invalid Gnutella header size", HSTL_GIBBERISH);
		msg = "Invalid size (greater than 64 KiB without flags)";
		goto not;		/* Probably just garbage */
	}

	if ((size_t) size + GTA_HEADER_SIZE != len) {
		msg = "Size mismatch";
		goto not;
	}

	/*
	 * We only support a subset of Gnutella message from UDP.  In particular,
	 * messages like HSEP data, BYE or QRP are not expected!
	 */

	switch (gnutella_header_get_function(header)) {
	case GTA_MSG_INIT:
	case GTA_MSG_INIT_RESPONSE:
	case GTA_MSG_VENDOR:
	case GTA_MSG_STANDARD:
	case GTA_MSG_PUSH_REQUEST:
	case GTA_MSG_SEARCH_RESULTS:
	case GTA_MSG_RUDP:
	case GTA_MSG_DHT:
		return TRUE;
	case GTA_MSG_SEARCH:
		if (settings_is_ultra() && GNET_PROPERTY(enable_guess)) {
			return TRUE;	/* GUESS query accepted */
		}
		msg = "Query from UDP refused";
		goto drop;
	}
	msg = "Gnutella message not processed from UDP";

drop:
	gnet_stats_count_dropped(n, MSG_DROP_UNEXPECTED);
	gnet_stats_inc_general(GNR_UDP_UNPROCESSED_MESSAGE);
	goto log;

too_large:
	gnet_stats_count_dropped(n, MSG_DROP_TOO_LARGE);
	gnet_stats_inc_general(GNR_UDP_UNPROCESSED_MESSAGE);
	goto log;

not:
	gnet_stats_inc_general(GNR_UDP_ALIEN_MESSAGE);
	/* FALL THROUGH */

log:
	if (GNET_PROPERTY(udp_debug)) {
		hostiles_flags_t flags;

		/*
		 * Do not pollute logs with errors from messages coming from known
		 * hostile addresses: no dumping of datagram, and flag the host as
		 * hostile anyway so that we know.
		 */

		flags = hostiles_check(s->addr);

		g_warning("UDP got invalid %sGnutella packet (%zu byte%s) "
			"\"%s\" %sfrom %s%s: %s",
			socket_udp_is_old(s) ? "OLD " : "",
			len, plural(len),
			len >= GTA_HEADER_SIZE ?
				gmsg_infostr_full_split(header, payload, len - GTA_HEADER_SIZE)
				: "<incomplete Gnutella header>",
			truncated ? "(truncated) " : "",
			(flags & HSTL_STATIC) ? "static hostile " : "",
			NULL == n ?
				host_addr_port_to_string(s->addr, s->port) :
				node_infostr(n),
			msg);

		if (len != 0 && !(flags & HSTL_STATIC)) {
			if (len <= GTA_HEADER_SIZE) {
				dump_hex(stderr, "UDP datagram", header, len);
			} else {
				iovec_t iov[2];
				iovec_set(&iov[0], header, GTA_HEADER_SIZE);
				iovec_set(&iov[1], payload, len - GTA_HEADER_SIZE);
				dump_hex_vec(stderr, "UDP datagram", iov, G_N_ELEMENTS(iov));
			}
		}
	}

	return FALSE;		/* Dropped */
}