/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ int send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length) { VLA(uint8_t, packet, 1 + length); packet[0] = TCP_PACKET_ONION_REQUEST; memcpy(packet + 1, data, length); return write_packet_TCP_secure_connection(con, packet, SIZEOF_VLA(packet), 0); }
static int handle_onion_recv_1(void *object, IP_Port dest, const uint8_t *data, uint16_t length) { TCP_Server *TCP_server = (TCP_Server *)object; uint32_t index = dest.ip.ip6.uint32[0]; if (index >= TCP_server->size_accepted_connections) { return 1; } TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[index]; if (con->identifier != dest.ip.ip6.uint64[1]) { return 1; } uint8_t packet[1 + length]; memcpy(packet + 1, data, length); packet[0] = TCP_PACKET_ONION_RESPONSE; if (write_packet_TCP_secure_connection(con, packet, sizeof(packet), 0) != 1) { return 1; } return 0; }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int send_disconnect_notification(TCP_Client_Connection *con, uint8_t id) { uint8_t packet[1 + 1]; packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; packet[1] = id; return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1); }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key) { uint8_t packet[1 + CRYPTO_PUBLIC_KEY_SIZE]; packet[0] = TCP_PACKET_ROUTING_REQUEST; memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1); }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int send_routing_response(TCP_Secure_Connection *con, uint8_t rpid, const uint8_t *public_key) { uint8_t data[1 + 1 + crypto_box_PUBLICKEYBYTES]; data[0] = TCP_PACKET_ROUTING_RESPONSE; data[1] = rpid; memcpy(data + 2, public_key, crypto_box_PUBLICKEYBYTES); return write_packet_TCP_secure_connection(con, data, sizeof(data)); }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int send_routing_response(TCP_Secure_Connection *con, uint8_t rpid, const uint8_t *public_key) { uint8_t data[1 + 1 + CRYPTO_PUBLIC_KEY_SIZE]; data[0] = TCP_PACKET_ROUTING_RESPONSE; data[1] = rpid; memcpy(data + 2, public_key, CRYPTO_PUBLIC_KEY_SIZE); return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); }
static void do_TCP_confirmed(TCP_Server *TCP_server) { #ifdef TCP_SERVER_USE_EPOLL if (TCP_server->last_run_pinged == unix_time()) { return; } TCP_server->last_run_pinged = unix_time(); #endif uint32_t i; for (i = 0; i < TCP_server->size_accepted_connections; ++i) { TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; if (conn->status != TCP_STATUS_CONFIRMED) { continue; } if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { uint8_t ping[1 + sizeof(uint64_t)]; ping[0] = TCP_PACKET_PING; uint64_t ping_id = random_64b(); if (!ping_id) { ++ping_id; } memcpy(ping + 1, &ping_id, sizeof(uint64_t)); int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping), 1); if (ret == 1) { conn->last_pinged = unix_time(); conn->ping_id = ping_id; } else { if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { kill_accepted(TCP_server, i); continue; } } } if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { kill_accepted(TCP_server, i); continue; } send_pending_data(conn); #ifndef TCP_SERVER_USE_EPOLL do_confirmed_recv(TCP_server, i); #endif } }
static void do_TCP_confirmed(TCP_Server *TCP_server) { uint32_t i; for (i = 0; i < TCP_server->size_accepted_connections; ++i) { TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; if (conn->status != TCP_STATUS_CONFIRMED) continue; if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { uint8_t ping[1 + sizeof(uint64_t)]; ping[0] = TCP_PACKET_PING; uint64_t ping_id = random_64b(); if (!ping_id) ++ping_id; memcpy(ping + 1, &ping_id, sizeof(uint64_t)); int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping)); if (ret == 1) { conn->last_pinged = unix_time(); conn->ping_id = ping_id; } } if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { kill_TCP_connection(conn); del_accepted(TCP_server, i); continue; } send_pending_data(conn); uint8_t packet[MAX_PACKET_SIZE]; int len; while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, packet, sizeof(packet)))) { if (len == -1) { kill_TCP_connection(conn); del_accepted(TCP_server, i); break; } if (handle_TCP_packet(TCP_server, i, packet, len) == -1) { kill_TCP_connection(conn); del_accepted(TCP_server, i); break; } } } }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure. */ int send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length) { if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { return -1; } VLA(uint8_t, packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); packet[0] = TCP_PACKET_OOB_SEND; memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); return write_packet_TCP_secure_connection(con, packet, SIZEOF_VLA(packet), 0); }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int send_ping_response(TCP_Client_Connection *con) { if (!con->ping_response_id) { return 1; } uint8_t packet[1 + sizeof(uint64_t)]; packet[0] = TCP_PACKET_PONG; memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t)); int ret; if ((ret = write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1)) == 1) { con->ping_response_id = 0; } return ret; }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure. */ int send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length) { if (con_id >= NUM_CLIENT_CONNECTIONS) { return -1; } if (con->connections[con_id].status != 2) { return -1; } if (send_ping_response(con) == 0 || send_ping_request(con) == 0) { return 0; } VLA(uint8_t, packet, 1 + length); packet[0] = con_id + NUM_RESERVED_PORTS; memcpy(packet + 1, data, length); return write_packet_TCP_secure_connection(con, packet, SIZEOF_VLA(packet), 0); }
/* return 0 on success. * return -1 on failure (connection must be killed). */ static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data, uint16_t length) { if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) return -1; TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; int other_index = get_TCP_connection_index(TCP_server, public_key); if (other_index != -1) { uint8_t resp_packet[1 + crypto_box_PUBLICKEYBYTES + length]; resp_packet[0] = TCP_PACKET_OOB_RECV; memcpy(resp_packet + 1, con->public_key, crypto_box_PUBLICKEYBYTES); memcpy(resp_packet + 1 + crypto_box_PUBLICKEYBYTES, data, length); write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet, sizeof(resp_packet)); } return 0; }
/* return 0 on success. * return -1 on failure (connection must be killed). */ static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data, uint16_t length) { if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { return -1; } TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; int other_index = get_TCP_connection_index(TCP_server, public_key); if (other_index != -1) { VLA(uint8_t, resp_packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); resp_packet[0] = TCP_PACKET_OOB_RECV; memcpy(resp_packet + 1, con->public_key, CRYPTO_PUBLIC_KEY_SIZE); memcpy(resp_packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet, SIZEOF_VLA(resp_packet), 0); } return 0; }
/* return 0 on success * return -1 on failure */ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *data, uint16_t length) { if (length == 0) return -1; TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; switch (data[0]) { case TCP_PACKET_ROUTING_REQUEST: { if (length != 1 + crypto_box_PUBLICKEYBYTES) return -1; return handle_TCP_routing_req(TCP_server, con_id, data + 1); } case TCP_PACKET_CONNECTION_NOTIFICATION: { if (length != 2) return -1; break; } case TCP_PACKET_DISCONNECT_NOTIFICATION: { if (length != 2) return -1; return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS); } case TCP_PACKET_PING: { if (length != 1 + sizeof(uint64_t)) return -1; uint8_t response[1 + sizeof(uint64_t)]; response[0] = TCP_PACKET_PONG; memcpy(response + 1, data + 1, sizeof(uint64_t)); write_packet_TCP_secure_connection(con, response, sizeof(response)); return 0; } case TCP_PACKET_PONG: { if (length != 1 + sizeof(uint64_t)) return -1; uint64_t ping_id; memcpy(&ping_id, data + 1, sizeof(uint64_t)); if (ping_id) { if (ping_id == con->ping_id) { con->ping_id = 0; } return 0; } else { return -1; } } case TCP_PACKET_OOB_SEND: { if (length <= 1 + crypto_box_PUBLICKEYBYTES) return -1; return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES, length - (1 + crypto_box_PUBLICKEYBYTES)); } case TCP_PACKET_ONION_REQUEST: { if (TCP_server->onion) { if (length <= 1 + crypto_box_NONCEBYTES + ONION_SEND_BASE * 2) return -1; IP_Port source; source.ip.family = TCP_ONION_FAMILY; source.ip.ip6.uint32[0] = con_id; source.ip.ip6.uint64[1] = con->identifier; onion_send_1(TCP_server->onion, data + 1 + crypto_box_NONCEBYTES, length - (1 + crypto_box_NONCEBYTES), source, data + 1); } return 0; } case TCP_PACKET_ONION_RESPONSE: { return -1; } default: { if (data[0] < NUM_RESERVED_PORTS) return -1; uint8_t c_id = data[0] - NUM_RESERVED_PORTS; if (c_id >= NUM_CLIENT_CONNECTIONS) return -1; if (con->connections[c_id].status == 0) return -1; if (con->connections[c_id].status != 2) return 0; uint32_t index = con->connections[c_id].index; uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS; uint8_t new_data[length]; memcpy(new_data, data, length); new_data[0] = other_c_id; int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length); if (ret == -1) return -1; return 0; } } return 0; }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int send_disconnect_notification(TCP_Secure_Connection *con, uint8_t id) { uint8_t data[2] = {TCP_PACKET_DISCONNECT_NOTIFICATION, id + NUM_RESERVED_PORTS}; return write_packet_TCP_secure_connection(con, data, sizeof(data)); }