diff --git a/net/net-crypto-aes.cpp b/net/net-crypto-aes.cpp index 33987578e2..c0027139b1 100644 --- a/net/net-crypto-aes.cpp +++ b/net/net-crypto-aes.cpp @@ -205,7 +205,7 @@ int aes_generate_nonce (char res[16]) { int aes_create_keys(aes_key_t *key, struct aes_session_key *R, int am_client, const char nonce_server[16], const char nonce_client[16], int client_timestamp, unsigned server_ip, unsigned short server_port, const unsigned char server_ipv6[16], unsigned client_ip, unsigned short client_port, - const unsigned char client_ipv6[16]) { + const unsigned char client_ipv6[16], bool is_ip_v6) { unsigned char str[16 + 16 + 4 + 4 + 2 + 6 + 4 + 2 + AES_KEY_MAX_LEN + 16 + 16 + 4 + 16 * 2]; int str_len; @@ -228,13 +228,10 @@ int aes_create_keys(aes_key_t *key, struct aes_session_key *R, int am_client, co memcpy(str + 54 + pwd_len, nonce_server, 16); str_len = 70 + pwd_len; - if (!server_ip) { - assert(!client_ip); + if (is_ip_v6) { memcpy(str + str_len, client_ipv6, 16); memcpy(str + str_len + 16, server_ipv6, 16); str_len += 32; - } else { - assert(client_ip); } memcpy(str + str_len, nonce_client, 16); diff --git a/net/net-crypto-aes.h b/net/net-crypto-aes.h index 53e13e8f36..d88dfac788 100644 --- a/net/net-crypto-aes.h +++ b/net/net-crypto-aes.h @@ -56,19 +56,22 @@ int aes_generate_nonce (char res[16]); int aes_create_keys(aes_key_t *key, struct aes_session_key *R, int am_client, const char nonce_server[16], const char nonce_client[16], int client_timestamp, unsigned server_ip, unsigned short server_port, const unsigned char server_ipv6[16], unsigned client_ip, unsigned short client_port, - const unsigned char client_ipv6[16]); + const unsigned char client_ipv6[16], bool is_ip_v6); int aes_create_udp_keys (const aes_key_t* key, aes_udp_session_key_t *R, const process_id_t *local_pid, const process_id_t *remote_pid, int generation); -static inline int aes_create_connection_keys(aes_key_t *key, struct aes_session_key *R, int am_client, char nonce_server[16], char nonce_client[16], - int client_timestamp, struct connection *c) { +static inline int aes_create_connection_keys(unsigned char protocol_version, aes_key_t *key, struct aes_session_key *R, int am_client, char nonce_server[16], char nonce_client[16], + int server_timestamp, int client_timestamp, struct connection *c) { uint32_t our_ip, remote_ip; uint16_t our_port, remote_port; uint8_t remote_ipv6[16] = {'\0'}; uint8_t our_ipv6[16] = {'\0'}; our_ip = remote_ip = our_port = remote_port = 0; - assert(c->local_endpoint.ss_family == c->remote_endpoint.ss_family); - switch (c->local_endpoint.ss_family) { + bool is_ipv6 = false; + + if (protocol_version == 0) { + assert(c->local_endpoint.ss_family == c->remote_endpoint.ss_family); + switch (c->local_endpoint.ss_family) { case AF_INET: our_ip = inet_sockaddr_address(&c->local_endpoint); remote_ip = inet_sockaddr_address(&c->remote_endpoint); @@ -80,15 +83,16 @@ static inline int aes_create_connection_keys(aes_key_t *key, struct aes_session_ memcpy(our_ipv6, inet6_sockaddr_address(&c->local_endpoint), sizeof(our_ipv6)); our_port = inet6_sockaddr_port(&c->local_endpoint); remote_port = inet6_sockaddr_port(&c->remote_endpoint); + is_ipv6 = true; break; default: assert(0); + } } return am_client - ? aes_create_keys(key, R, am_client, nonce_server, nonce_client, client_timestamp, remote_ip, remote_port, remote_ipv6, our_ip, our_port, our_ipv6) - - : aes_create_keys(key, R, am_client, nonce_server, nonce_client, client_timestamp, our_ip, our_port, our_ipv6, remote_ip, remote_port, remote_ipv6); + ? aes_create_keys(key, R, am_client, nonce_server, nonce_client, client_timestamp, protocol_version == 0 ? remote_ip : server_timestamp, remote_port, remote_ipv6, our_ip, our_port, our_ipv6, is_ipv6) + : aes_create_keys(key, R, am_client, nonce_server, nonce_client, client_timestamp, protocol_version == 0 ? our_ip : server_timestamp, our_port, our_ipv6, remote_ip, remote_port, remote_ipv6, is_ipv6); } static inline int get_crypto_key_id(const aes_key_t *key) { diff --git a/net/net-memcache-client.cpp b/net/net-memcache-client.cpp index 5a8cbd408a..3c187b3350 100644 --- a/net/net-memcache-client.cpp +++ b/net/net-memcache-client.cpp @@ -611,7 +611,7 @@ int mcc_start_crypto (struct connection *c, char *key, int key_len) { struct aes_session_key aes_keys; - if (aes_create_connection_keys (default_aes_key, &aes_keys, 1, nonce_in, D->nonce, D->nonce_time, c) < 0) { + if (aes_create_connection_keys (0, default_aes_key, &aes_keys, 1, nonce_in, D->nonce, 0, D->nonce_time, c) < 0) { return -1; } diff --git a/net/net-memcache-server.cpp b/net/net-memcache-server.cpp index 6beebaefd5..a0bb10d361 100644 --- a/net/net-memcache-server.cpp +++ b/net/net-memcache-server.cpp @@ -1029,7 +1029,7 @@ int mcs_init_crypto (struct connection *c, char *key, int key_len) { struct aes_session_key aes_keys; - if (aes_create_connection_keys (default_aes_key, &aes_keys, 0, nonce_out, nonce_in, utime, c) < 0) { + if (aes_create_connection_keys (0, default_aes_key, &aes_keys, 0, nonce_out, nonce_in, 0, utime, c) < 0) { return -1; } diff --git a/net/net-mysql-client.cpp b/net/net-mysql-client.cpp index 9a569c842e..1065b37f66 100644 --- a/net/net-mysql-client.cpp +++ b/net/net-mysql-client.cpp @@ -567,7 +567,7 @@ int sqlc_init_crypto (struct connection *c, char *key, int key_len) { struct aes_session_key aes_keys; - if (aes_create_connection_keys (default_aes_key, &aes_keys, 1, nonce_in, nonce_out, utime, c) < 0) { + if (aes_create_connection_keys (0, default_aes_key, &aes_keys, 1, nonce_in, nonce_out, 0, utime, c) < 0) { return -1; } diff --git a/net/net-tcp-rpc-client.cpp b/net/net-tcp-rpc-client.cpp index 0ff3138566..a3e6064fd6 100644 --- a/net/net-tcp-rpc-client.cpp +++ b/net/net-tcp-rpc-client.cpp @@ -73,9 +73,9 @@ int tcp_rpcc_default_execute (struct connection *c, int op, raw_message_t *raw) tvkprintf(net_connections, 3, "rpcc_execute: fd=%d, op=%d, len=%d\n", c->fd, op, raw->total_bytes); if (op == TL_RPC_PING && raw->total_bytes == 12) { c->last_response_time = precise_now; - static int Q[12]; + int Q[12]; assert (rwm_fetch_data (raw, Q, 12) == 12); - static int P[12]; + int P[12]; P[0] = TL_RPC_PONG; P[1] = Q[1]; P[2] = Q[2]; @@ -90,18 +90,24 @@ int tcp_rpcc_default_execute (struct connection *c, int op, raw_message_t *raw) static int tcp_rpcc_process_nonce_packet (struct connection *c, raw_message_t *msg) { struct tcp_rpc_data *D = TCP_RPC_DATA(c); - static struct tcp_rpc_nonce_packet P; + struct tcp_rpc_nonce_packet P{}; int res; if (D->packet_num != -2 || D->packet_type != RPC_NONCE) { return -2; } - if (D->packet_len != sizeof (struct tcp_rpc_nonce_packet)) { + if (D->packet_len < sizeof (P) || D->packet_len >= 1024) { return -3; } + int excess_data_size = D->packet_len - sizeof(P); // fields from newer protocol version - assert (rwm_fetch_data (msg, &P, D->packet_len) == D->packet_len); - tvkprintf(net_connections, 4, "Processing nonce packet, crypto schema: %d, key select: %d\n", P.crypto_schema, P.key_select); + assert (rwm_fetch_data (msg, &P, sizeof(P)) == sizeof(P)); + assert (rwm_fetch_data (msg, 0, excess_data_size) == excess_data_size); + tvkprintf(net_connections, 4, "Processing nonce packet, crypto schema: %d, version: %d, excess_data: %d, key select: %d\n", P.crypto_schema, P.protocol_version, excess_data_size, P.key_select); + + if (P.protocol_version > 1) { // server must not reply with version > client + return -3; + } switch (P.crypto_schema) { case RPC_CRYPTO_NONE: @@ -127,7 +133,7 @@ static int tcp_rpcc_process_nonce_packet (struct connection *c, raw_message_t *m if (abs (P.crypto_ts - D->nonce_time) > 30) { return -6; //less'om } - res = TCP_RPCC_FUNC(c)->rpc_start_crypto (c, P.crypto_nonce, P.key_select); + res = TCP_RPCC_FUNC(c)->rpc_start_crypto (c, &P); if (res < 0) { return -6; } @@ -142,14 +148,13 @@ static int tcp_rpcc_process_nonce_packet (struct connection *c, raw_message_t *m static int tcp_rpcc_send_handshake_packet (struct connection *c) { tvkprintf(net_connections, 4, "tcp_rpcc_send_handshake_packet\n"); struct tcp_rpc_data *D = TCP_RPC_DATA (c); - static struct tcp_rpc_handshake_packet P; + struct tcp_rpc_handshake_packet P{}; if (!PID.ip) { init_client_PID(c->local_endpoint.ss_family == AF_INET ? inet_sockaddr_address(&c->local_endpoint): 0); if (!PID.ip) { PID.ip = get_my_ipv4 (); } } - memset (&P, 0, sizeof (P)); P.type = RPC_HANDSHAKE; P.flags = default_rpc_flags & RPC_CRYPTO_USE_CRC32C; if (!D->remote_pid.port) { @@ -167,11 +172,10 @@ static int tcp_rpcc_send_handshake_packet (struct connection *c) { } static int tcp_rpcc_send_handshake_error_packet (struct connection *c, int error_code) { - static struct tcp_rpc_handshake_error_packet P; + struct tcp_rpc_handshake_error_packet P{}; if (!PID.pid) { init_client_PID(inet_sockaddr_address(&c->local_endpoint)); } - memset (&P, 0, sizeof (P)); P.type = RPC_HANDSHAKE_ERROR; P.error_code = error_code; memcpy (&P.sender_pid, &PID, sizeof (PID)); @@ -185,11 +189,11 @@ static int tcp_rpcc_process_handshake_packet (struct connection *c, raw_message_ tvkprintf(net_connections, 4, "tcp_rpcc_process_handshake_packet\n"); struct tcp_rpc_data *D = TCP_RPC_DATA(c); - static struct tcp_rpc_handshake_packet P; + struct tcp_rpc_handshake_packet P{}; if (D->packet_num != -1 || D->packet_type != RPC_HANDSHAKE) { return -2; } - if (D->packet_len != sizeof (struct tcp_rpc_handshake_packet)) { + if (D->packet_len != sizeof (P)) { tcp_rpcc_send_handshake_error_packet (c, -3); return -3; } @@ -227,17 +231,23 @@ int tcp_rpcc_parse_execute (struct connection *c) { int len; while (true) { - len = c->in.total_bytes; + len = c->in.total_bytes; if (len <= 0) { break; } if (!D->packet_len) { - if (len < 4) { + if (len < D->packet_v1_padding + 4) { c->status = conn_reading_answer; - return 4 - len; + return D->packet_v1_padding + 4 - len; + } + if (D->packet_v1_padding) { + assert(D->packet_v1_padding < 4); + assert(rwm_fetch_data(&c->in, 0, D->packet_v1_padding) == D->packet_v1_padding); + D->packet_v1_padding = 0; } assert (rwm_fetch_lookup (&c->in, &D->packet_len, 4) == 4); - if (D->packet_len <= 0 || (D->packet_len & 3) || (D->packet_len > TCP_RPCC_FUNC(c)->max_packet_len && TCP_RPCC_FUNC(c)->max_packet_len > 0)) { + // We skip checks for len&3 == 0 for protocol version 0, because there is little value in it. + if (D->packet_len > TCP_RPCC_FUNC(c)->max_packet_len && TCP_RPCC_FUNC(c)->max_packet_len > 0) { tvkprintf(net_connections, 1, "error while parsing packet: bad packet length %d\n", D->packet_len); c->status = conn_error; c->error = -1; @@ -259,7 +269,6 @@ int tcp_rpcc_parse_execute (struct connection *c) { c->status = conn_reading_answer; return D->packet_len - len; } - raw_message_t msg; if (c->in.total_bytes == D->packet_len) { @@ -339,6 +348,9 @@ int tcp_rpcc_parse_execute (struct connection *c) { } D->in_packet_num++; + if (c->crypto) { + D->packet_v1_padding = (-D->packet_len) & 3; + } D->packet_len = 0; if (c->status == conn_running) { c->status = conn_wait_answer; @@ -421,10 +433,10 @@ int tcp_rpcc_init_fake_crypto (struct connection *c) { return -1; } - static struct tcp_rpc_nonce_packet buf; - memset (&buf, 0, sizeof (buf)); + struct tcp_rpc_nonce_packet buf{}; buf.type = RPC_NONCE; buf.crypto_schema = RPC_CRYPTO_NONE; + buf.protocol_version = 1; // ask for latest version we support tcp_rpc_conn_send_data (c, sizeof (buf), &buf); @@ -477,13 +489,13 @@ int tcp_rpcc_init_crypto (struct connection *c) { aes_generate_nonce (TCP_RPC_DATA(c)->nonce); - static struct tcp_rpc_nonce_packet buf; - memset (&buf, 0, sizeof (buf)); + struct tcp_rpc_nonce_packet buf{}; memcpy (buf.crypto_nonce, TCP_RPC_DATA(c)->nonce, 16); buf.crypto_ts = TCP_RPC_DATA(c)->nonce_time; buf.type = RPC_NONCE; buf.key_select = get_crypto_key_id (default_aes_key); buf.crypto_schema = (TCP_RPC_DATA(c)->crypto_flags & RPC_CRYPTO_ALLOW_UNENCRYPTED) ? RPC_CRYPTO_NONE_OR_AES : RPC_CRYPTO_AES; + buf.protocol_version = 1; // ask for latest version we support tcp_rpc_conn_send_data (c, sizeof (buf), &buf); @@ -494,9 +506,9 @@ int tcp_rpcc_init_crypto (struct connection *c) { return 1; } -int tcp_rpcc_start_crypto (struct connection *c, char *nonce, int key_select) { +int tcp_rpcc_start_crypto (struct connection *c, struct tcp_rpc_nonce_packet *P) { struct tcp_rpc_data *D = TCP_RPC_DATA(c); - tvkprintf(net_connections, 4, "rpcc_start_crypto: key_select = %d\n", key_select); + tvkprintf(net_connections, 4, "rpcc_start_crypto: key_select = %d\n", P->key_select); if (c->crypto) { return -1; @@ -506,13 +518,13 @@ int tcp_rpcc_start_crypto (struct connection *c, char *nonce, int key_select) { return -1; } - if (!key_select || key_select != get_crypto_key_id (default_aes_key)) { + if (!P->key_select || P->key_select != get_crypto_key_id (default_aes_key)) { return -1; } struct aes_session_key aes_keys; - if (aes_create_connection_keys (default_aes_key, &aes_keys, 1, nonce, D->nonce, D->nonce_time, c) < 0) { + if (aes_create_connection_keys (P->protocol_version, default_aes_key, &aes_keys, 1, P->crypto_nonce, D->nonce, P->crypto_ts, D->nonce_time, c) < 0) { return -1; } @@ -529,7 +541,7 @@ void tcp_rpcc_flush_crypto (struct connection *c) { tvkprintf(net_connections, 4, "rpcc_flush_packet: padding with %d bytes\n", pad_bytes); if (pad_bytes > 0) { assert (!(pad_bytes & 3)); - static int pad_str[3] = {4, 4, 4}; + int pad_str[3] = {4, 4, 4}; assert (pad_bytes <= 12); assert (rwm_push_data (&c->out, pad_str, pad_bytes) == pad_bytes); } @@ -552,7 +564,7 @@ int tcp_rpcc_flush (struct connection *c) { tvkprintf(net_connections, 4, "rpcs_flush: padding with %d bytes\n", pad_bytes); if (pad_bytes > 0) { assert (!(pad_bytes & 3)); - static int pad_str[3] = {4, 4, 4}; + int pad_str[3] = {4, 4, 4}; assert (pad_bytes <= 12); assert (rwm_push_data (&c->out, pad_str, pad_bytes) == pad_bytes); } diff --git a/net/net-tcp-rpc-client.h b/net/net-tcp-rpc-client.h index 434c04135d..dae5de5ced 100644 --- a/net/net-tcp-rpc-client.h +++ b/net/net-tcp-rpc-client.h @@ -8,6 +8,7 @@ #include #include "net/net-connections.h" +#include "net/net-tcp-rpc-common.h" #include "net/net-msg.h" struct tcp_rpc_client_functions { @@ -17,7 +18,7 @@ struct tcp_rpc_client_functions { int (*flush_packet)(struct connection *c); /* execute this to push query to server */ int (*rpc_check_perm)(struct connection *c); /* 1 = allow unencrypted, 2 = allow encrypted */ int (*rpc_init_crypto)(struct connection *c); /* 1 = ok; -1 = no crypto */ - int (*rpc_start_crypto)(struct connection *c, char *nonce, int key_select); /* 1 = ok; -1 = no crypto */ + int (*rpc_start_crypto)(struct connection *c, struct tcp_rpc_nonce_packet *P); /* 1 = ok; -1 = no crypto */ int (*rpc_wakeup)(struct connection *c); int (*rpc_alarm)(struct connection *c); int (*rpc_ready)(struct connection *c); @@ -38,7 +39,7 @@ int tcp_rpcc_flush_packet_later (struct connection *c); int tcp_rpcc_default_check_perm (struct connection *c); int tcp_rpcc_default_check_perm_crypto (struct connection *c); int tcp_rpcc_init_crypto (struct connection *c); -int tcp_rpcc_start_crypto (struct connection *c, char *nonce, int key_select); +int tcp_rpcc_start_crypto (struct connection *c, struct tcp_rpc_nonce_packet *P); int default_tcp_rpc_client_check_ready(struct connection *c); #define TCP_RPCC_FUNC(c) ((struct tcp_rpc_client_functions *) ((c)->extra)) diff --git a/net/net-tcp-rpc-common.cpp b/net/net-tcp-rpc-common.cpp index a07f4a5807..2e7f079e42 100644 --- a/net/net-tcp-rpc-common.cpp +++ b/net/net-tcp-rpc-common.cpp @@ -27,7 +27,6 @@ OPTION_PARSER(OPT_RPC, "no-crc32c", no_argument, "Force use of CRC32 instead of void tcp_rpc_conn_send (struct connection *c, raw_message_t *raw, int flags) { tvkprintf(net_connections, 4, "%s: sending message of size %d to conn fd=%d\n", __func__, raw->total_bytes, c->fd); - assert (!(raw->total_bytes & 3)); int Q[2]; Q[0] = raw->total_bytes + 12; Q[1] = TCP_RPC_DATA(c)->out_packet_num ++; @@ -40,11 +39,15 @@ void tcp_rpc_conn_send (struct connection *c, raw_message_t *raw, int flags) { rwm_push_data_front (&r, Q, 8); unsigned crc32 = rwm_custom_crc32 (&r, r.total_bytes, TCP_RPC_DATA(c)->custom_crc_partial); rwm_push_data (&r, &crc32, 4); + if (c->crypto) { + int packet_v1_padding = (-raw->total_bytes) & 3; + char padding[3]{}; + rwm_push_data (&r, &padding, packet_v1_padding); + } rwm_union (&c->out, &r); } void tcp_rpc_conn_send_data (struct connection *c, int len, void *Q) { - assert (!(len & 3)); raw_message_t r; assert (rwm_create (&r, Q, len) == len); tcp_rpc_conn_send (c, &r, 0); diff --git a/net/net-tcp-rpc-common.h b/net/net-tcp-rpc-common.h index f4f04b9658..ebd5974efc 100644 --- a/net/net-tcp-rpc-common.h +++ b/net/net-tcp-rpc-common.h @@ -17,7 +17,9 @@ struct tcp_rpc_nonce_packet { int type; int key_select; /* least significant 32 bits of key to use */ - int crypto_schema; /* 0 = NONE, 1 = AES */ + unsigned char crypto_schema; /* 0 = NONE, 1 = AES */ + unsigned char protocol_version; + unsigned short protocol_flags; int crypto_ts; char crypto_nonce[16]; }; @@ -43,6 +45,7 @@ void tcp_rpc_conn_send_data (struct connection *c, int len, void *Q); /* in conn->custom_data */ struct tcp_rpc_data { int packet_len; + int packet_v1_padding; int packet_num; int packet_type; int packet_crc32; @@ -67,6 +70,8 @@ struct tcp_rpc_data { #define TCP_RPC_DATA(c) ((struct tcp_rpc_data *) ((c)->custom_data)) +static_assert(sizeof(connection_t::custom_data) >= sizeof(tcp_rpc_data)); + #define RPC_CRYPTO_ALLOW_UNENCRYPTED 0x00000001 #define RPC_CRYPTO_ALLOW_ENCRYPTED 0x00000002 #define RPC_CRYPTO_ALLOW_MASK (RPC_CRYPTO_ALLOW_UNENCRYPTED | RPC_CRYPTO_ALLOW_ENCRYPTED) diff --git a/net/net-tcp-rpc-server.cpp b/net/net-tcp-rpc-server.cpp index a41501cc28..a72676f099 100644 --- a/net/net-tcp-rpc-server.cpp +++ b/net/net-tcp-rpc-server.cpp @@ -102,9 +102,9 @@ int tcp_rpcs_default_execute (struct connection *c, int op, raw_message_t *raw) tvkprintf(net_connections, 4, "rpcs_execute: fd=%d, op=%d, len=%d\n", c->fd, op, raw->total_bytes); if (op == TL_RPC_PING && raw->total_bytes == 12) { c->last_response_time = precise_now; - static int Q[12]; + int Q[12]; assert (rwm_fetch_data (raw, Q, 12) == 12); - static int P[12]; + int P[12]; P[0] = TL_RPC_PONG; P[1] = Q[1]; P[2] = Q[2]; @@ -120,17 +120,25 @@ int tcp_rpcs_default_execute (struct connection *c, int op, raw_message_t *raw) static int tcp_rpcs_process_nonce_packet (struct connection *c, raw_message_t *msg) { struct tcp_rpc_data *D = TCP_RPC_DATA(c); - static struct tcp_rpc_nonce_packet P; + struct tcp_rpc_nonce_packet P{}; int res; if (D->packet_num != -2 || D->packet_type != RPC_NONCE) { return -2; } - if (D->packet_len != sizeof(struct tcp_rpc_nonce_packet)) { + if (D->packet_len < sizeof (P) || D->packet_len >= 1024) { return -3; } + int excess_data_size = D->packet_len - sizeof(P); // fields from newer protocol version + + assert (rwm_fetch_data (msg, &P, sizeof(P)) == sizeof(P)); + assert (rwm_fetch_data (msg, 0, excess_data_size) == excess_data_size); + // tvkprintf(net_connections, 4, "Processing nonce packet from client, crypto schema: %d, version: %d, excess_data: %d, key select: %d\n", P.crypto_schema, P.protocol_version, excess_data_size, P.key_select); + + if (P.protocol_version > 1) { // client can ask for any version, we set maximum we support + P.protocol_version = 1; + } - assert (rwm_fetch_data(msg, &P, D->packet_len) == D->packet_len); int crypto_schema = P.crypto_schema; if (crypto_schema == RPC_CRYPTO_NONE_OR_AES) { if (D->crypto_flags & RPC_CRYPTO_ALLOW_UNENCRYPTED) { @@ -190,9 +198,8 @@ static int tcp_rpcs_process_nonce_packet (struct connection *c, raw_message_t *m static int tcp_rpcs_send_handshake_packet (struct connection *c) { struct tcp_rpc_data *D = TCP_RPC_DATA(c); - static struct tcp_rpc_handshake_packet P; + struct tcp_rpc_handshake_packet P{}; assert (PID.pid); - memset (&P, 0, sizeof (P)); P.type = RPC_HANDSHAKE; P.flags = D->crypto_flags & RPC_CRYPTO_USE_CRC32C; memcpy (&P.sender_pid, &PID, sizeof (struct process_id)); @@ -205,9 +212,8 @@ static int tcp_rpcs_send_handshake_packet (struct connection *c) { } static int tcp_rpcs_send_handshake_error_packet (struct connection *c, int error_code) { - static struct tcp_rpc_handshake_error_packet P; + struct tcp_rpc_handshake_error_packet P{}; assert (PID.pid); - memset (&P, 0, sizeof (P)); P.type = RPC_HANDSHAKE_ERROR; P.error_code = error_code; memcpy (&P.sender_pid, &PID, sizeof (PID)); @@ -220,7 +226,7 @@ static int tcp_rpcs_send_handshake_error_packet (struct connection *c, int error static int tcp_rpcs_process_handshake_packet (struct connection *c, raw_message_t *msg) { struct tcp_rpc_data *D = TCP_RPC_DATA(c); - static struct tcp_rpc_handshake_packet P; + struct tcp_rpc_handshake_packet P{}; if (!PID.ip) { init_server_PID(inet_sockaddr_address(&c->local_endpoint), inet_sockaddr_port(&c->local_endpoint)); @@ -231,7 +237,7 @@ static int tcp_rpcs_process_handshake_packet (struct connection *c, raw_message_ if (D->packet_num != -1 || D->packet_type != RPC_HANDSHAKE) { return -2; } - if (D->packet_len != sizeof (struct tcp_rpc_handshake_packet)) { + if (D->packet_len != sizeof (P)) { tcp_rpcs_send_handshake_error_packet (c, -3); return -3; } @@ -271,9 +277,14 @@ int tcp_rpcs_parse_execute (struct connection *c) { } // fprintf (stderr, "in while : packet_len=%d, total_ready_bytes=%d; cptr=%p; c->status=%d\n", D->packet_len, len, c->Q.cptr, c->status); if (!D->packet_len) { - if (len < 4) { + if (len < D->packet_v1_padding + 4) { c->status = conn_reading_query; - return 4 - len; + return D->packet_v1_padding + 4 - len; + } + if (D->packet_v1_padding) { + assert(D->packet_v1_padding < 4); + assert(rwm_fetch_data(&c->in, 0, D->packet_v1_padding) == D->packet_v1_padding); + D->packet_v1_padding = 0; } assert (rwm_fetch_lookup (&c->in, &D->packet_len, 4) == 4); if (D->crypto_flags & 512) { @@ -293,13 +304,13 @@ int tcp_rpcs_parse_execute (struct connection *c) { memset (c->custom_data, 0, sizeof (c->custom_data)); c->type = static_cast(TCP_RPCS_FUNC(c)->memcache_fallback_type); c->extra = TCP_RPCS_FUNC(c)->memcache_fallback_extra; - + assert (!c->out.total_bytes && !c->out_p.total_bytes && !c->in_u.total_bytes); rwm_free (&c->out); rwm_free (&c->out_p); rwm_free (&c->in_u); c->flags &= ~C_RAWMSG; - + init_builtin_buffer (&c->In, c->in_buff, BUFF_SIZE); init_builtin_buffer (&c->Out, c->out_buff, BUFF_SIZE); @@ -320,13 +331,13 @@ int tcp_rpcs_parse_execute (struct connection *c) { memset (c->custom_data, 0, sizeof (c->custom_data)); c->type = static_cast(TCP_RPCS_FUNC(c)->http_fallback_type); c->extra = TCP_RPCS_FUNC(c)->http_fallback_extra; - + assert (!c->out.total_bytes && !c->out_p.total_bytes && !c->in_u.total_bytes); rwm_free (&c->out); rwm_free (&c->out_p); rwm_free (&c->in_u); c->flags &= ~C_RAWMSG; - + init_builtin_buffer (&c->In, c->in_buff, BUFF_SIZE); init_builtin_buffer (&c->Out, c->out_buff, BUFF_SIZE); @@ -342,12 +353,16 @@ int tcp_rpcs_parse_execute (struct connection *c) { nbit_set (&c->Q, &c->In); return c->type->parse_execute (c); } + } + if (D->packet_len >= 0x40000000) { + // IDK why this limit separate from TCP_RPCS_FUNC(c)->max_packet_len was set, keeping it for now, tvkprintf(net_connections, 1, "error while parsing packet: bad packet length %d\n", D->packet_len); c->status = conn_error; c->error = -1; return 0; } } + // We skip checks for len&3 == 0 for protocol version 0, because there is little value, actually. if (D->packet_len == 4) { assert (rwm_fetch_data (&c->in, 0, 4) == 4); D->packet_len = 0; @@ -455,6 +470,9 @@ int tcp_rpcs_parse_execute (struct connection *c) { //assert ((c->pending_queries && (c->status == conn_wait_net || c->status == conn_wait_aio)) || (!c->pending_queries && c->status == conn_expect_query)); assert (c->status == conn_wait_net || (c->pending_queries && c->status == conn_wait_aio) || (!c->pending_queries && c->status == conn_expect_query)); + if (c->crypto) { + D->packet_v1_padding = (-D->packet_len) & 3; + } D->packet_len = 0; if (c->status != conn_expect_query) { break; @@ -532,16 +550,15 @@ int tcp_rpcs_init_accepted_nohs (struct connection *c) { return TCP_RPCS_FUNC(c)->rpc_ready ? TCP_RPCS_FUNC(c)->rpc_ready (c) : 0; } -int tcp_rpcs_init_fake_crypto (struct connection *c) { +int tcp_rpcs_init_fake_crypto (struct connection *c, unsigned char protocol_version) { if (!(TCP_RPC_DATA(c)->crypto_flags & RPC_CRYPTO_ALLOW_UNENCRYPTED)) { return -1; } - static struct tcp_rpc_nonce_packet buf; - memset (&buf, 0, sizeof (buf)); + struct tcp_rpc_nonce_packet buf{}; buf.type = RPC_NONCE; buf.crypto_schema = RPC_CRYPTO_NONE; - + buf.protocol_version = protocol_version; tcp_rpc_conn_send_data (c, sizeof (buf), &buf); assert ((TCP_RPC_DATA(c)->crypto_flags & RPC_CRYPTO_ENCRYPTED_MASK) == 0); TCP_RPC_DATA(c)->crypto_flags |= RPC_CRYPTO_NONCE_SENT; @@ -583,7 +600,7 @@ int tcp_rpcs_init_crypto (struct connection *c, struct tcp_rpc_nonce_packet *P) } if ((D->crypto_flags & (RPC_CRYPTO_ALLOW_ENCRYPTED|RPC_CRYPTO_ALLOW_UNENCRYPTED)) == RPC_CRYPTO_ALLOW_UNENCRYPTED) { - return tcp_rpcs_init_fake_crypto (c); + return tcp_rpcs_init_fake_crypto (c, P->protocol_version); } if ((D->crypto_flags & (RPC_CRYPTO_ALLOW_ENCRYPTED|RPC_CRYPTO_ALLOW_UNENCRYPTED)) != RPC_CRYPTO_ALLOW_ENCRYPTED) { @@ -598,7 +615,7 @@ int tcp_rpcs_init_crypto (struct connection *c, struct tcp_rpc_nonce_packet *P) struct aes_session_key aes_keys; - if (aes_create_connection_keys (default_aes_key, &aes_keys, 0, D->nonce, P->crypto_nonce, P->crypto_ts, c) < 0) { + if (aes_create_connection_keys (P->protocol_version, default_aes_key, &aes_keys, 0, D->nonce, P->crypto_nonce, D->nonce_time, P->crypto_ts, c) < 0) { return -1; } @@ -606,11 +623,11 @@ int tcp_rpcs_init_crypto (struct connection *c, struct tcp_rpc_nonce_packet *P) return -1; } - static struct tcp_rpc_nonce_packet buf; - memset (&buf, 0, sizeof (buf)); + struct tcp_rpc_nonce_packet buf{}; memcpy (buf.crypto_nonce, D->nonce, 16); buf.crypto_ts = D->nonce_time; buf.type = RPC_NONCE; + buf.protocol_version = P->protocol_version; buf.key_select = get_crypto_key_id (default_aes_key); buf.crypto_schema = RPC_CRYPTO_AES; @@ -637,7 +654,7 @@ int tcp_rpcs_flush_packet (struct connection *c) { tvkprintf(net_connections, 4, "tcp_rpcs_flush_packet: padding with %d bytes\n", pad_bytes); if (pad_bytes > 0) { assert (!(pad_bytes & 3)); - static int pad_str[3] = {4, 4, 4}; + int pad_str[3] = {4, 4, 4}; assert (pad_bytes <= 12); assert (rwm_push_data (&c->out, pad_str, pad_bytes) == pad_bytes); } @@ -651,7 +668,7 @@ int tcp_rpcs_flush (struct connection *c) { tvkprintf(net_connections, 4, "rpcs_flush: padding with %d bytes\n", pad_bytes); if (pad_bytes > 0) { assert (!(pad_bytes & 3)); - static int pad_str[3] = {4, 4, 4}; + int pad_str[3] = {4, 4, 4}; assert (pad_bytes <= 12); assert (rwm_push_data (&c->out, pad_str, pad_bytes) == pad_bytes); } diff --git a/runtime/rpc.cpp b/runtime/rpc.cpp index ecfaf06853..4e9b4a9d51 100644 --- a/runtime/rpc.cpp +++ b/runtime/rpc.cpp @@ -139,12 +139,6 @@ void rpc_parse(const int32_t* new_rpc_data, int32_t new_rpc_data_len) { } bool f$rpc_parse(const string& new_rpc_data) noexcept { - if (new_rpc_data.size() % sizeof(int) != 0) { - php_warning("Wrong parameter \"new_rpc_data\" of len %d passed to function rpc_parse", (int)new_rpc_data.size()); - last_rpc_error = "Result's length is not divisible by 4"; - last_rpc_error_code = TL_ERROR_RESPONSE_SYNTAX; - return false; - } rpc_parse_save_backup(); @@ -666,7 +660,6 @@ int64_t rpc_send_impl(const class_instance& conn, double timeou } store_int(-1); // reserve for crc32 - php_assert(data_buf.size() % sizeof(int) == 0); const auto [opt_new_wrapper, cur_wrapper_size, opt_actor_id_warning_info, opt_ignore_result_warning_msg]{regularize_wrappers(data_buf.c_str() + sizeof(RpcHeaders), conn.get()->actor_id, ignore_answer)}; diff --git a/vkext/vkext-rpc.cpp b/vkext/vkext-rpc.cpp index 6f5512327c..39052772fe 100644 --- a/vkext/vkext-rpc.cpp +++ b/vkext/vkext-rpc.cpp @@ -1403,7 +1403,7 @@ static int rpc_write(struct rpc_connection *c, long long qid, double timeout, bo /* }}} */ static int rpc_nonce_execute(struct rpc_server *server, char *answer, int answer_len) { /* {{{ */ - if (answer_len != sizeof(struct rpc_nonce) || server->inbound_packet_num != -1) { + if (answer_len >= 1024 || answer_len < sizeof(struct rpc_nonce) || server->inbound_packet_num != -1) { rpc_server_seterror(server, "Bad nonce packet", 0); return -1; } @@ -1464,7 +1464,8 @@ static int rpc_handshake_send(struct rpc_server *server, double timeout) { /* {{ static int rpc_nonce_send(struct rpc_server *server, double timeout) { /* {{{ */ struct rpc_nonce S = { .key_select = 0, - .crypto_schema = 0 + .crypto_schema = 0, + .protocol_version = 1 // ask for latest version we support }; //server->outbuf = buffer_create (sizeof (S)); @@ -1534,7 +1535,7 @@ static int rpc_read(struct rpc_server *server, int force_block_read, double time assert (rpc_read_in(server, (char *)tmp, 12, timeout) == 12); int len = tmp[0]; - if (len < 20 || (len & 3) || len > RPC_MAX_QUERY_LEN) { + if (len < 20 || len > RPC_MAX_QUERY_LEN) { rpc_server_seterror(server, "Invalid length of answer", 0); END_TIMER (rpc_read); return -1; diff --git a/vkext/vkext-rpc.h b/vkext/vkext-rpc.h index 17e114cf16..681d1a3509 100644 --- a/vkext/vkext-rpc.h +++ b/vkext/vkext-rpc.h @@ -238,7 +238,9 @@ extern int global_errnum; #define GLOBAL_GENERATION 0 struct rpc_nonce { int key_select; /* least significant 32 bits of key to use */ - int crypto_schema; /* 0 = NONE, 1 = AES */ + unsigned char crypto_schema; /* 0 = NONE, 1 = AES */ + unsigned char protocol_version; + unsigned short protocol_flags; int crypto_ts; char crypto_nonce[16]; };