/* return length of received packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) { if (*next_packet_length == 0) { uint16_t len = read_TCP_length(sock); if (len == (uint16_t)~0) return -1; if (len == 0) return 0; *next_packet_length = len; } if (max_len + crypto_box_MACBYTES < *next_packet_length) return -1; uint8_t data_encrypted[*next_packet_length]; int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); if (len_packet != *next_packet_length) return 0; *next_packet_length = 0; int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); if (len + crypto_box_MACBYTES != len_packet) return -1; increment_nonce(recv_nonce); return len; }
/* return length of recieved packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t max_len) { if (con->next_packet_length == 0) { uint16_t len = read_length(con->sock); if (len == (uint16_t)~0) return -1; if (len == 0) return 0; con->next_packet_length = len; } if (max_len + crypto_box_MACBYTES < con->next_packet_length) return -1; uint8_t data_encrypted[con->next_packet_length]; int len_packet = read_TCP_packet(con->sock, data_encrypted, con->next_packet_length); if (len_packet != con->next_packet_length) return 0; con->next_packet_length = 0; int len = decrypt_data_fast(con->shared_key, con->recv_nonce, data_encrypted, len_packet, data); if (len + crypto_box_MACBYTES != len_packet) return -1; increment_nonce(con->recv_nonce); return len; }
/* return 1 if connection handshake was handled correctly. * return 0 if we didn't get it yet. * return -1 if the connection must be killed. */ static int read_connection_handshake(TCP_Secure_Connection *con, const uint8_t *self_secret_key) { uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE]; int len = 0; if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) { return handle_TCP_handshake(con, data, len, self_secret_key); } return 0; }
/* return 1 on success. * return 0 if no data received. * return -1 on failure (connection refused). */ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) { uint8_t data[2]; int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); if (ret == -1) { return 0; } if (data[0] == 5 && data[1] == 0) { // TODO(irungentoo): magic numbers return 1; } return -1; }
/* return length of received packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ int read_packet_TCP_secure_connection(Socket sock, uint16_t *next_packet_length, const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) { if (*next_packet_length == 0) { uint16_t len = read_TCP_length(sock); if (len == (uint16_t)~0) { return -1; } if (len == 0) { return 0; } *next_packet_length = len; } if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) { return -1; } VLA(uint8_t, data_encrypted, *next_packet_length); int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); if (len_packet != *next_packet_length) { return 0; } *next_packet_length = 0; int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); if (len + CRYPTO_MAC_SIZE != len_packet) { return -1; } increment_nonce(recv_nonce); return len; }
/* Run the TCP connection */ void do_TCP_connection(TCP_Client_Connection *TCP_connection, void *userdata) { unix_time_update(); if (TCP_connection->status == TCP_CLIENT_DISCONNECTED) { return; } if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { if (send_pending_data(TCP_connection) == 0) { int ret = proxy_http_read_connection_response(TCP_connection); if (ret == -1) { TCP_connection->kill_at = 0; TCP_connection->status = TCP_CLIENT_DISCONNECTED; } if (ret == 1) { generate_handshake(TCP_connection); TCP_connection->status = TCP_CLIENT_CONNECTING; } } } if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { if (send_pending_data(TCP_connection) == 0) { int ret = socks5_read_handshake_response(TCP_connection); if (ret == -1) { TCP_connection->kill_at = 0; TCP_connection->status = TCP_CLIENT_DISCONNECTED; } if (ret == 1) { proxy_socks5_generate_connection_request(TCP_connection); TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; } } } if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { if (send_pending_data(TCP_connection) == 0) { int ret = proxy_socks5_read_connection_response(TCP_connection); if (ret == -1) { TCP_connection->kill_at = 0; TCP_connection->status = TCP_CLIENT_DISCONNECTED; } if (ret == 1) { generate_handshake(TCP_connection); TCP_connection->status = TCP_CLIENT_CONNECTING; } } } if (TCP_connection->status == TCP_CLIENT_CONNECTING) { if (send_pending_data(TCP_connection) == 0) { TCP_connection->status = TCP_CLIENT_UNCONFIRMED; } } if (TCP_connection->status == TCP_CLIENT_UNCONFIRMED) { uint8_t data[TCP_SERVER_HANDSHAKE_SIZE]; int len = read_TCP_packet(TCP_connection->sock, data, sizeof(data)); if (sizeof(data) == len) { if (handle_handshake(TCP_connection, data) == 0) { TCP_connection->kill_at = ~0; TCP_connection->status = TCP_CLIENT_CONFIRMED; } else { TCP_connection->kill_at = 0; TCP_connection->status = TCP_CLIENT_DISCONNECTED; } } } if (TCP_connection->status == TCP_CLIENT_CONFIRMED) { do_confirmed_TCP(TCP_connection, userdata); } if (TCP_connection->kill_at <= unix_time()) { TCP_connection->status = TCP_CLIENT_DISCONNECTED; } }