Exemple #1
0
static void udp_pending(gpointer data, gint source, PurpleInputCondition cond)
{
	PurpleConnection *gc = NULL;
	qq_data *qd;
	guint8 *buf;
	gint buf_len;

	gc = (PurpleConnection *) data;
	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
	qd = (qq_data *) gc->proto_data;

	if(cond != PURPLE_INPUT_READ) {
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Socket error"));
		return;
	}

	buf = g_newa(guint8, MAX_PACKET_SIZE);

	/* here we have UDP proxy suppport */
	buf_len = read(source, buf, MAX_PACKET_SIZE);
	if (buf_len <= 0) {
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Unable to read from socket"));
		return;
	}

	/* keep alive will be sent in 30 seconds since last_receive
	 *  QQ need a keep alive packet in every 60 seconds
	 gc->last_received = time(NULL);
	*/

	if (buf_len < QQ_UDP_HEADER_LENGTH) {
		if (buf[0] != QQ_PACKET_TAG || buf[buf_len - 1] != QQ_PACKET_TAIL) {
			qq_hex_dump(PURPLE_DEBUG_ERROR, "UDP_PENDING",
					buf, buf_len,
					"Received packet is too short, or no header and tail tag");
			return;
		}
	}

	/* packet_process may call disconnect and destory data like conn
	 * do not call packet_process before jump,
	 * break if packet_process return FALSE */
	packet_process(gc, buf, buf_len);
}
Exemple #2
0
/* default process, decrypt and dump */
static void process_unknown_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
{
	gchar *msg;

	g_return_if_fail(data != NULL && data_len != 0);

	qq_show_packet(title, data, data_len);

	qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
			data, data_len,
			">>> [%d] %s -> [default] decrypt and dump",
			seq, qq_get_cmd_desc(cmd));

	msg = g_strdup_printf("Unknown command 0x%02X, %s", cmd, qq_get_cmd_desc(cmd));
	//purple_notify_info(gc, _("QQ Error"), title, msg);
	g_free(msg);
}
Exemple #3
0
static void _qq_process_recv_file_ctl_packet(PurpleConnection *gc, guint8 *data, gint data_len)
{
	gint bytes ;
	gint decryped_bytes;
	qq_file_header fh;
	guint8 *decrypted_data;
	gint decrypted_len;
	qq_data *qd = (qq_data *) gc->proto_data;
	guint16 packet_type;
	guint16 seq;
	guint8 hellobyte;
	ft_info *info = (ft_info *) qd->xfer->data;

	bytes = 0;
	bytes += _qq_get_file_header(&fh, data + bytes);

	decrypted_data = g_newa(guint8, data_len);
	decrypted_len = qq_decrypt(decrypted_data, data, data_len, qd->session_md5);
	if ( decrypted_len <= 0 ) {
		purple_debug_error("QQ", "Error decrypt rcv file ctrl packet\n");
		return;
	}

	/* only for debug info */
	decryped_bytes = 16;	/* skip md5 section */
	decryped_bytes += qq_get16(&packet_type, decrypted_data + decryped_bytes);
	decryped_bytes += qq_get16(&seq, decrypted_data + decryped_bytes);
	decryped_bytes += 4+1+1+19+1;	/* skip something */

	purple_debug_info("QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type));
	qq_hex_dump(PURPLE_DEBUG_INFO, "QQ",
		decrypted_data, decrypted_len,
		"decrypted control packet received:");

	switch (packet_type) {
		case QQ_FILE_CMD_NOTIFY_IP_ACK:
			decryped_bytes = 0;
			qq_get_conn_info(info, decrypted_data + decryped_bytes);
			/* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0);
			break;
		case QQ_FILE_CMD_SENDER_SAY_HELLO:
			/* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */
			decryped_bytes += 47;
			decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes);
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO_ACK, fh.sender_uid, hellobyte);
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO, fh.sender_uid, 0);
			break;
		case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK:
			/* I'm sender, do nothing */
			break;
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO:
			/* I'm sender, ack the hello packet and send the first data */
			decryped_bytes += 47;
			decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes);
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK, fh.sender_uid, hellobyte);
			_qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_BASIC_INFO, 0, 0, NULL, 0);
			break;
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK:
			/* I'm receiver, do nothing */
			break;
		case QQ_FILE_CMD_PING:
			/* I'm receiver, ack the PING */
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PONG, fh.sender_uid, 0);
			break;
		case QQ_FILE_CMD_PONG:
			qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0);
			break;
		default:
			purple_debug_info("QQ", "unprocess file command %d\n", packet_type);
	}
}
Exemple #4
0
/* send a file to udp channel with QQ_FILE_CONTROL_PACKET_TAG */
void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, guint32 to_uid, guint8 hellobyte)
{
	qq_data *qd;
	gint bytes, bytes_expected, encrypted_len;
	guint8 *raw_data, *encrypted;
	time_t now;
	ft_info *info;

	qd = (qq_data *) gc->proto_data;
	info = (ft_info *) qd->xfer->data;

	raw_data = g_newa (guint8, 61);
	bytes = 0;

	now = time(NULL);

	bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16);
	bytes += qq_put16(raw_data + bytes, packet_type);
	switch (packet_type) {
		case QQ_FILE_CMD_SENDER_SAY_HELLO:
		case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_NOTIFY_IP_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO:
			bytes += qq_put16(raw_data + bytes, info->send_seq);
			break;
		default:
			bytes += qq_put16(raw_data + bytes, ++qd->send_seq);
	}
	bytes += qq_put32(raw_data + bytes, (guint32) now);
	bytes += qq_put8(raw_data + bytes, 0x00);
	bytes += qq_put8(raw_data + bytes, qd->my_icon);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put32(raw_data + bytes, 0x00000000);
	bytes += qq_put16(raw_data + bytes, 0x0000);
	bytes += qq_put8(raw_data + bytes, 0x00);
	/* 0x65: send a file, 0x6b: send a custom face */
	bytes += qq_put8(raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME temp by gfhuang */
	switch (packet_type)
	{
		case QQ_FILE_CMD_SENDER_SAY_HELLO:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO:
		case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK:
		case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK:
			bytes += qq_put8(raw_data + bytes, 0x00);
			bytes += qq_put8(raw_data + bytes, hellobyte);
			bytes_expected = 48;
			break;
		case QQ_FILE_CMD_PING:
		case QQ_FILE_CMD_PONG:
		case QQ_FILE_CMD_NOTIFY_IP_ACK:
			bytes += qq_fill_conn_info(raw_data, info);
			bytes_expected = 61;
			break;
		default:
			purple_debug_info("QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n",
					packet_type);
			bytes_expected = 0;
	}

	if (bytes != bytes_expected) {
		purple_debug_error("QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d\n",
				bytes_expected, bytes);
		return;
	}

	qq_hex_dump(PURPLE_DEBUG_INFO, "QQ",
		raw_data, bytes,
		"sending packet[%s]:", qq_get_file_cmd_desc(packet_type));

	encrypted = g_newa(guint8, bytes + 17);
	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, info->file_session_key);
	/*debug: try to decrypt it */

#if 0
	guint8 *buf;
	int buflen;
	hex_dump = hex_dump_to_str(encrypted, encrypted_len);
	purple_debug_info("QQ", "encrypted packet: \n%s\n", hex_dump);
	g_free(hex_dump);
	buf = g_newa(guint8, MAX_PACKET_SIZE);
	buflen = encrypted_len;
	if (qq_crypt(DECRYPT, encrypted, encrypted_len, info->file_session_key, buf, &buflen)) {
		purple_debug_info("QQ", "decrypt success\n");
	   if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0)
			purple_debug_info("QQ", "checksum ok\n");

		hex_dump = hex_dump_to_str(buf, buflen);
		purple_debug_info("QQ", "decrypted packet: \n%s\n", hex_dump);
		g_free(hex_dump);
	 } else {
		purple_debug_info("QQ", "decrypt fail\n");
	}
#endif

	purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type));
	_qq_send_file(gc, encrypted, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid);
}