Beispiel #1
0
/* Decrypts the given data.
 * Returns the decrypted data length.
 *
 * The output is preallocated with the maximum allowed data size.
 */
int
_gnutls_decrypt(gnutls_session_t session,
		gnutls_datum_t *ciphertext,
		gnutls_datum_t *output,
		content_type_t *type,
		record_parameters_st *params,
		gnutls_uint64 *sequence)
{
	int ret;
	const version_entry_st *vers = get_version(session);

	if (ciphertext->size == 0)
		return 0;

	if (vers && vers->tls13_sem)
		ret =
		    decrypt_packet_tls13(session, ciphertext,
					 output, type, params,
					 sequence);
	else
		ret =
		    decrypt_packet(session, ciphertext,
				   output, *type, params,
				   sequence);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return ret;
}
Beispiel #2
0
void take_encypt_string(char* dest, buffer_t *buffer)
{
	size_t len;
	buffer_t string;

	clear_buffer(&string);
	take_buffer(&len, buffer, sizeof(len));
	take_buffer(string.buff, buffer, len);
	decrypt_packet(&string,len);
	take_buffer(dest, &string, len);
}
void take_encypt_string(buffer_t *buffer, char* dest)
{
	size_t len;
	buffer_t string;

	clear_buffer(&string);
	take_buffer(buffer, &len, sizeof(len));
	take_buffer(buffer, string.buff, len);
	decrypt_packet(&string,len);
	take_buffer(&string, dest, len);
}
Beispiel #4
0
/* Non-blocking function reading available portion of a packet into the
 * ses's buffer, decrypting the length if encrypted, decrypting the
 * full portion if possible */
void read_packet() {

	int len;
	unsigned int maxlen;
	unsigned char blocksize;

	TRACE(("enter read_packet"));
	blocksize = ses.keys->recv_algo_crypt->blocksize;
	
	if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
		/* In the first blocksize of a packet */

		/* Read the first blocksize of the packet, so we can decrypt it and
		 * find the length of the whole packet */
		read_packet_init();

		/* If we don't have the length of decryptreadbuf, we didn't read
		 * a whole blocksize and should exit */
		if (ses.decryptreadbuf->len == 0) {
			TRACE(("leave read_packet: packetinit done"));
			return;
		}
	}

	/* Attempt to read the remainder of the packet, note that there
	 * mightn't be any available (EAGAIN) */
	assert(ses.readbuf != NULL);
	maxlen = ses.readbuf->len - ses.readbuf->pos;
	len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen);
	buf_incrpos(ses.readbuf, len);

	if (len == 0) {
		dropbear_close("remote host closed connection");
	}

	if (len < 0) {
		if (errno == EINTR || errno == EAGAIN) {
			TRACE(("leave read_packet: EINTR or EAGAIN"));
			return;
		} else {
			dropbear_exit("error reading");
		}
	}

	if ((unsigned int)len == maxlen) {
		/* The whole packet has been read */
		decrypt_packet();
		/* The main select() loop in session.h will process_packet() to
		 * handle the packet contents... */
	}
	TRACE(("leave read_packet"));
}
Beispiel #5
0
void handle_packet(const uchar *data, ushort size)
{
	uchar *buf;
	int *bufsize;
	ushort psize;
	packet_t *pkt;

	if (_fromsv) {
		buf = _svbuf;
		bufsize = &_svbufsize;
	} else {
		buf = _clbuf;
		bufsize = &_clbufsize;
	}

	if (size+*bufsize >= BUFSIZE) {
		log_msg("dbg", "warning: buffer size exceeded in handle_packet.\r\n");
		return;
	}

	memcpy(buf+*bufsize, data, size);
	*bufsize += size;
	psize = *(ushort *)buf;

	if (psize < 3) {
		log_msg("dbg", "warning: malformed packet (%.2X) incorrect size: %hu.\r\n", *(ushort *)data, psize);
		return;
	}

	if (*bufsize >= psize) {
		do {
			pkt = alloc_packet(buf, psize);
			if (decrypt_packet(pkt, _fromsv, &_isfirst) != 0) {
				log_msg("dbg", "error: decryption failed, missed key packet?\r\n");
			} else {
				if (_fromsv) {
					handle_sv_packet(pkt);
				} else {
					handle_cl_packet(pkt);
				}
			}
			free(pkt);
			*bufsize -= psize;
			memcpy(buf, buf+psize, *bufsize);
			psize = *(ushort *)buf;
		} while (*bufsize >= psize && *bufsize > 0);
	}
}
/*!
 * @brief Receive a new packet on the given remote endpoint.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to a pointer that will receive the \c Packet data.
 * @return An indication of the result of processing the transmission request.
 */
static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet)
{
	DWORD headerBytes = 0, payloadBytesLeft = 0, res;
	PacketHeader header = { 0 };
	LONG bytesRead;
	BOOL inHeader = TRUE;
	PUCHAR packetBuffer = NULL;
	PUCHAR payload = NULL;
	ULONG payloadLength;
	NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx;

	lock_acquire(remote->lock);

	dprintf("[PIPE PACKET RECEIVE] reading in the header from pipe handle: %p", ctx->pipe);
	// Read the packet length
	while (inHeader)
	{
		if (!ReadFile(ctx->pipe, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, &bytesRead, NULL))
		{
			SetLastError(ERROR_NOT_FOUND);
			goto out;
		}

		headerBytes += bytesRead;

		if (headerBytes != sizeof(PacketHeader))
		{
			vdprintf("[PIPE] More bytes required");
			continue;
		}

		inHeader = FALSE;
	}

	if (headerBytes != sizeof(PacketHeader))
	{
		dprintf("[PIPE] we didn't get enough header bytes");
		goto out;
	}

	vdprintf("[PIPE] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]);

#ifdef DEBUGTRACE
	PUCHAR h = (PUCHAR)&header;
	dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]",
		h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]);
#endif

	// At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data
	// from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following:
	// XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it
	// isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big).
	if (header.xor_key[3] == 0)
	{
		// looks like we have a metsrv instance, time to ignore it.
		int length = *(int*)&header.xor_key[0];
		dprintf("[PIPE] discovered a length header, assuming it's metsrv of length %d", length);

		int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD);
		char* buffer = (char*)malloc(bytesToRead);
		read_raw_bytes_to_buffer(ctx, buffer, bytesToRead, &bytesRead);
		free(buffer);

		// did something go wrong.
		if (bytesToRead != bytesRead)
		{
			dprintf("[PIPE] Failed to read all bytes when flushing the buffer: %u vs %u", bytesToRead, bytesRead);
			goto out;
		}

		// indicate success, but don't return a packet for processing
		SetLastError(ERROR_SUCCESS);
		*packet = NULL;
	}
	else
	{
		vdprintf("[PIPE] XOR key looks fine, moving on");
		// xor the header data
		xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key));
#ifdef DEBUGTRACE
		PUCHAR h = (PUCHAR)&header;
		dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]",
			h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]);
#endif

		// if we don't have a GUID yet, we need to take the one given in the packet
		if (is_null_guid(remote->orig_config->session.session_guid))
		{
			memcpy(remote->orig_config->session.session_guid, header.session_guid, sizeof(remote->orig_config->session.session_guid));
		}

		payloadLength = ntohl(header.length) - sizeof(TlvHeader);
		dprintf("[PIPE] Payload length is %u 0x%08x", payloadLength, payloadLength);
		DWORD packetSize = sizeof(PacketHeader) + payloadLength;
		dprintf("[PIPE] total buffer size for the packet is %u 0x%08x", packetSize, packetSize);
		payloadBytesLeft = payloadLength;

		// Allocate the payload
		if (!(packetBuffer = (PUCHAR)malloc(packetSize)))
		{
			dprintf("[PIPE] Failed to create the packet buffer");
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			goto out;
		}
		dprintf("[PIPE] Allocated packet buffer at %p", packetBuffer);

		// we're done with the header data, so we need to re-encode it, as the packet decryptor is going to
		// handle the extraction for us.
		xor_bytes(header.xor_key, (LPBYTE)&header.session_guid[0], sizeof(PacketHeader) - sizeof(header.xor_key));
		// Copy the packet header stuff over to the packet
		memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&header, sizeof(PacketHeader));

		payload = packetBuffer + sizeof(PacketHeader);

		// Read the payload
		res = read_raw_bytes_to_buffer(ctx, payload, payloadLength, &bytesRead);
		dprintf("[PIPE] wanted %u read %u", payloadLength, bytesRead);

		// Didn't finish?
		if (bytesRead != payloadLength)
		{
			dprintf("[PIPE] Failed to get all the payload bytes");
			SetLastError(res);
			goto out;
		}

		vdprintf("[PIPE] decrypting packet");
		SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize));

		free(packetBuffer);
		packetBuffer = NULL;
	}
out:
	res = GetLastError();

	// Cleanup
	if (packetBuffer)
	{
		free(packetBuffer);
	}

	lock_release(remote->lock);

	return res;
}
/*!
 * @brief Windows-specific function to receive a new packet via one of the HTTP libs (WinInet or WinHTTP).
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to a pointer that will receive the \c Packet data.
 * @return An indication of the result of processing the transmission request.
 */
static DWORD packet_receive_http(Remote *remote, Packet **packet)
{
	DWORD headerBytes = 0, payloadBytesLeft = 0, res;
	Packet *localPacket = NULL;
	PacketHeader header;
	LONG bytesRead;
	BOOL inHeader = TRUE;
	PUCHAR packetBuffer = NULL;
	ULONG payloadLength;
	HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;

	HINTERNET hReq;
	BOOL hRes;
	DWORD retries = 5;

	lock_acquire(remote->lock);

	hReq = ctx->create_req(ctx, TRUE, "PACKET RECEIVE");
	if (hReq == NULL)
	{
		goto out;
	}

	vdprintf("[PACKET RECEIVE HTTP] sending GET");
	hRes = ctx->send_req(ctx, hReq, NULL, 0);

	if (!hRes)
	{
		dprintf("[PACKET RECEIVE HTTP] Failed send_req: %d %d", GetLastError(), WSAGetLastError());
		SetLastError(ERROR_NOT_FOUND);
		goto out;
	}

	vdprintf("[PACKET RECEIVE HTTP] Waiting to see the response ...");
	if (ctx->receive_response && !ctx->receive_response(hReq))
	{
		vdprintf("[PACKET RECEIVE] Failed receive: %d", GetLastError());
		SetLastError(ERROR_NOT_FOUND);
		goto out;
	}

	SetLastError(ctx->validate_response(hReq, ctx));

	if (GetLastError() != ERROR_SUCCESS)
	{
		goto out;
	}

	// Read the packet length
	retries = 3;
	vdprintf("[PACKET RECEIVE HTTP] Start looping through the receive calls");
	while (inHeader && retries > 0)
	{
		retries--;
		if (!ctx->read_response(hReq, (PUCHAR)&header + headerBytes, sizeof(PacketHeader)-headerBytes, &bytesRead))
		{
			dprintf("[PACKET RECEIVE HTTP] Failed HEADER read_response: %d", GetLastError());
			SetLastError(ERROR_NOT_FOUND);
			goto out;
		}

		vdprintf("[PACKET RECEIVE NHTTP] Data received: %u bytes", bytesRead);

		// If the response contains no data, this is fine, it just means the
		// remote side had nothing to tell us. Indicate this through a
		// ERROR_EMPTY response code so we can update the timestamp.
		if (bytesRead == 0)
		{
			SetLastError(ERROR_EMPTY);
			goto out;
		}

		headerBytes += bytesRead;

		if (headerBytes != sizeof(PacketHeader))
		{
			continue;
		}

		inHeader = FALSE;
	}

	if (headerBytes != sizeof(PacketHeader))
	{
		dprintf("[PACKET RECEIVE HTTP] headerBytes not valid");
		SetLastError(ERROR_NOT_FOUND);
		goto out;
	}

	dprintf("[PACKET RECEIVE HTTP] decoding header");
	PacketHeader encodedHeader;
	memcpy(&encodedHeader, &header, sizeof(PacketHeader));
	xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key));

#ifdef DEBUGTRACE
	PUCHAR h = (PUCHAR)&header;
	vdprintf("[HTTP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]",
		   h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]);
#endif

	payloadLength = ntohl(header.length) - sizeof(TlvHeader);
	vdprintf("[REC HTTP] Payload length is %d", payloadLength);
	DWORD packetSize = sizeof(PacketHeader) + payloadLength;
	vdprintf("[REC HTTP] total buffer size for the packet is %d", packetSize);
	payloadBytesLeft = payloadLength;

	// Allocate the payload
	if (!(packetBuffer = (PUCHAR)malloc(packetSize)))
	{
		dprintf("[REC HTTP] Failed to create the packet buffer");
		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
		goto out;
	}
	dprintf("[REC HTTP] Allocated packet buffer at %p", packetBuffer);

	// Copy the packet header stuff over to the packet
	memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader));

	LPBYTE payload = packetBuffer + sizeof(PacketHeader);

	// Read the payload
	retries = payloadBytesLeft;
	while (payloadBytesLeft > 0 && retries > 0)
	{
		vdprintf("[PACKET RECEIVE HTTP] reading more data from the body...");
		retries--;
		if (!ctx->read_response(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead))
		{
			dprintf("[PACKET RECEIVE] Failed BODY read_response: %d", GetLastError());
			SetLastError(ERROR_NOT_FOUND);
			goto out;
		}

		if (!bytesRead)
		{
			vdprintf("[PACKET RECEIVE HTTP] no bytes read, bailing out");
			SetLastError(ERROR_NOT_FOUND);
			goto out;
		}

		vdprintf("[PACKET RECEIVE HTTP] bytes read: %u", bytesRead);
		payloadBytesLeft -= bytesRead;
	}

	// Didn't finish?
	if (payloadBytesLeft)
	{
		goto out;
	}

#ifdef DEBUGTRACE
	h = (PUCHAR)&header.session_guid[0];
	dprintf("[HTTP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
		h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]);
#endif

	if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0)
	{
		dprintf("[HTTP] Session GUIDs match (or packet guid is null), decrypting packet");
		SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize));
	}
	else
	{
		dprintf("[HTTP] Session GUIDs don't match, looking for a pivot");
		PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid);
		if (pivotCtx != NULL)
		{
			dprintf("[HTTP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)");
			SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize));

			// mark this packet buffer as NULL as the thread will clean it up
			packetBuffer = NULL;
			*packet = NULL;
		}
		else
		{
			dprintf("[HTTP] Session GUIDs don't match, can't find pivot!");
		}
	}

out:
	res = GetLastError();

	dprintf("[HTTP] Cleaning up");
	SAFE_FREE(packetBuffer);

	// Cleanup on failure
	if (res != ERROR_SUCCESS)
	{
		SAFE_FREE(localPacket);
	}

	if (hReq)
	{
		ctx->close_req(hReq);
	}

	lock_release(remote->lock);

	dprintf("[HTTP] Packet receive finished");

	return res;
}
Beispiel #8
0
int process_packet( qqclient* qq, qqpacket* p, bytebuffer* buf )
{
	if( !decrypt_packet( qq, p, buf ) )
		return -1;
	if( qq->log_packet ){
		DBG("[%d] recv packet ver:%x cmd: %x seqno: %x", qq->number, p->version, p->command, p->seqno );
		hex_dump( p->buf->data, p->buf->len );
	}
	switch( p->command ){
	case QQ_CMD_TOUCH:
		prot_login_touch_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_REQUEST:
		prot_login_request_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_VERIFY:
		prot_login_verify_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_GET_INFO:
		prot_login_get_info_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_A4:
		prot_login_a4_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_GET_LIST:
		prot_login_get_list_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_SEND_INFO:
		prot_login_send_info_reply( qq, p );
		break;
	case QQ_CMD_E9:
		prot_login_e9_reply( qq, p );
		break; 
	case QQ_CMD_EA:
		prot_login_ea_reply( qq, p );
		break; 
	case QQ_CMD_EC:
		prot_login_ec_reply( qq, p );
		break; 
	case QQ_CMD_ED:
		prot_login_ed_reply( qq, p );
		break; 
	case QQ_CMD_KEEP_ALIVE:
		prot_user_keep_alive_reply( qq, p );
		break;
	case QQ_CMD_RECV_IM_09:
	case QQ_CMD_RECV_IM:
		prot_im_recv_msg( qq, p );
		break;
	case QQ_CMD_CHANGE_STATUS:
		prot_user_change_status_reply( qq, p );
		break;
#ifndef NO_BUDDY_INFO
	case QQ_CMD_GET_BUDDY_LIST:
		prot_buddy_update_list_reply( qq, p );
		break;
	case QQ_CMD_GET_BUDDY_ONLINE:
		prot_buddy_update_online_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_STATUS:
		prot_buddy_status( qq, p );
		break;
#endif
#ifndef NO_QUN_INFO
	case QQ_CMD_QUN_CMD:
		prot_qun_cmd_reply( qq, p );
		break;
#endif
	case QQ_CMD_GET_KEY:
		prot_user_get_key_reply( qq, p );
		break;
	case QQ_CMD_GET_NOTICE:
		prot_user_get_notice_reply( qq, p );
		break;
	case QQ_CMD_CHECK_IP:
		prot_user_check_ip_reply( qq, p );
		break;
#ifndef NO_BUDDY_DETAIL_INFO
	case QQ_CMD_GET_BUDDY_SIGN:
		prot_buddy_update_signiture_reply( qq, p );
		break;
	case QQ_CMD_ACCOUNT:
		prot_buddy_update_account_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_ALIAS:
		prot_buddy_update_alias_reply( qq, p );
		break;
	case QQ_CMD_GET_BUDDY_EXTRA_INFO:
		prot_buddy_get_extra_info_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_INFO:
		prot_buddy_get_info_reply( qq, p );
		break;
#endif
#ifndef NO_GROUP_INFO
	case QQ_CMD_GROUP_LABEL:
		prot_group_download_labels_reply( qq, p );
		break;
#endif
	case QQ_CMD_SEND_IM:
		break;
	case QQ_CMD_BROADCAST:
		prot_misc_broadcast( qq, p );
		break;
	case QQ_CMD_GET_LEVEL:
		prot_user_get_level_reply( qq, p );
		break;
	case QQ_CMD_ADDBUDDY_REQUEST:
		prot_buddy_request_addbuddy_reply( qq, p );
		break;
	case QQ_CMD_ADDBUDDY_VERIFY:
		prot_buddy_verify_addbuddy_reply( qq, p );
		break;
	case QQ_CMD_REQUEST_TOKEN:
		prot_user_request_token_reply( qq, p );
		break;
	case QQ_CMD_DEL_BUDDY:
		prot_buddy_del_buddy_reply( qq, p );
		break;
	default:
		DBG("unknown cmd: %x", p->command );
		hex_dump( p->buf->data, p->buf->len );
		break;
	}
	return 0;
}
Beispiel #9
0
int process_packet( qqclient* qq, qqpacket* p, bytebuffer* buf )
{
	if( !decrypt_packet( qq, p, buf ) )
		return -1;
	if( qq->log_packet ){
		DBG("[%d] recv packet ver:%x cmd: %x seqno: %x", qq->number, p->version, p->command, p->seqno );
		hex_dump( p->buf->data, p->buf->len );
	}

	// memcpy(qq->mimnetwork->m_libevabuffer,p->buf->data,p->buf->len);
	qq->mimnetwork->m_packet=p;

	switch( p->command ){
	case QQ_CMD_TOUCH:
		prot_login_touch_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_REQUEST:
		prot_login_request_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_VERIFY:
		prot_login_verify_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_GET_INFO:
		prot_login_get_info_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_A4:
		prot_login_a4_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_GET_LIST:
		prot_login_get_list_reply( qq, p );
		break;
	case QQ_CMD_LOGIN_SEND_INFO:
		prot_login_send_info_reply( qq, p );
		break;
	case QQ_CMD_E9:
		prot_login_e9_reply( qq, p );
		break; 
	case QQ_CMD_EA:
		prot_login_ea_reply( qq, p );
		break; 
	case QQ_CMD_EC:
		prot_login_ec_reply( qq, p );
		break; 
	case QQ_CMD_ED:
		prot_login_ed_reply( qq, p );
		break; 
	case QQ_CMD_KEEP_ALIVE:
		prot_user_keep_alive_reply( qq, p );
		break;
	case QQ_CMD_RECV_IM_09:
	case QQ_CMD_RECV_IM:
		// MirandaQQ handles message by itself due to userhead/emoticon stuff
		// however ack is better handled by myqq3 in case of proto change
		 prot_im_recv_msg( qq, p );
		//prot_im_ack_recv( qq, p );
		break;
	case QQ_CMD_CHANGE_STATUS:
		prot_user_change_status_reply( qq, p );
		break;
#ifndef NO_BUDDY_INFO
	case QQ_CMD_GET_BUDDY_LIST:
		prot_buddy_update_list_reply( qq, p );
		break;
	case QQ_CMD_GET_BUDDY_ONLINE:
		prot_buddy_update_online_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_STATUS:
		prot_buddy_status( qq, p );
		break;
#endif
#ifndef NO_QUN_INFO
	case QQ_CMD_QUN_CMD:
		prot_qun_cmd_reply( qq, p );
		break;
#endif
	case QQ_CMD_GET_KEY:
		prot_user_get_key_reply( qq, p );
		break;
	case QQ_CMD_GET_NOTICE:
		prot_user_get_notice_reply( qq, p );
		break;
	case QQ_CMD_CHECK_IP:
		prot_user_check_ip_reply( qq, p );
		break;
#ifndef NO_BUDDY_DETAIL_INFO
	case QQ_CMD_GET_BUDDY_SIGN:
		prot_buddy_update_signiture_reply( qq, p );
		break;
	case QQ_CMD_ACCOUNT:
		prot_buddy_update_account_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_ALIAS:
		prot_buddy_update_alias_reply( qq, p );
		break;
	case QQ_CMD_GET_BUDDY_EXTRA_INFO:
		prot_buddy_get_extra_info_reply( qq, p );
		break;
	case QQ_CMD_BUDDY_INFO:
		prot_buddy_get_info_reply( qq, p );
		break;
#endif
#ifndef NO_GROUP_INFO
	case QQ_CMD_GROUP_LABEL:
		prot_group_download_labels_reply( qq, p );
		break;
#endif
	case QQ_CMD_SEND_IM:
		break;
	case QQ_CMD_BROADCAST:
		prot_misc_broadcast( qq, p );
		break;
	case QQ_CMD_GET_LEVEL:
		prot_user_get_level_reply( qq, p );
		break;
	case QQ_CMD_ADDBUDDY_REQUEST:
		prot_buddy_request_addbuddy_reply( qq, p );
		break;
	case QQ_CMD_ADDBUDDY_VERIFY:
		prot_buddy_verify_addbuddy_reply( qq, p );
		break;
	case QQ_CMD_REQUEST_TOKEN:
		prot_user_request_token_reply( qq, p );
		break;
	case QQ_CMD_DEL_BUDDY:
		prot_buddy_del_buddy_reply( qq, p );
		break;
	case QQ_CMD_SEARCH_UID:
		prot_buddy_search_uid_reply( qq, p );
		break;
	case 0xa6: // Weather
		prot_weather_reply( qq, p );
		break;
	default:
		DBG("unknown cmd: %x", p->command );
		hex_dump( p->buf->data, p->buf->len );
		break;
	}

	/*
	qq->mimnetwork->m_packet=p;
	qq->mimnetwork->processPacket(qq->mimnetwork->m_libevabuffer,p->buf->len);
	*/

	return 0;
}