#include "nano_attachment.h" #include #include #include #include #include #include #include #include "nano_attachment_sender.h" #include "nano_attachment_metric.h" #include "nano_initializer.h" #include "nano_configuration.h" #include "nano_utils.h" #include "attachment_types.h" #include "nano_blockpage.h" #include "compression_utils.h" #include "nano_compression.h" NanoAttachment * InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd) { NanoAttachment *attachment = malloc(sizeof(NanoAttachment)); if (attachment == NULL) { return NULL; } memset(attachment, 0, sizeof(NanoAttachment)); attachment->shared_verdict_signal_path[0] = '\0'; attachment->worker_id = worker_id; attachment->num_of_workers = num_of_workers; attachment->nano_user_id = getuid(); attachment->nano_group_id = getgid(); attachment->registration_socket = -1; attachment->registration_state = NOT_REGISTERED; attachment->attachment_type = attachment_type; attachment->nano_service_ipc = NULL; attachment->comm_socket = -1; attachment->logging_data = NULL; if (set_docker_id(attachment) == NANO_ERROR) { write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not evaluate container id"); close_logging_fd(attachment); free(attachment); return NULL; } if (set_logging_fd(attachment, logging_fd) == NANO_ERROR) { free(attachment); return NULL; } attachment->logging_data = initLoggingData( attachment->logging_fd, DBG_LEVEL_INFO, attachment->worker_id ); if (attachment->logging_data == NULL) { write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Failed to initialize logging data"); return NULL; } if (set_unique_id(attachment) == NANO_ERROR) { write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not evaluate unique name"); close_logging_fd(attachment); free(attachment); return NULL; } attachment->is_configuration_updated = NANO_ERROR; attachment->current_config_version = 0; attachment->fail_mode_verdict = NANO_OK; attachment->fail_mode_delayed_verdict = NANO_OK; attachment->dbg_level = DBG_LEVEL_INFO; attachment->num_of_connection_attempts = 0; attachment->fail_open_timeout = 50; attachment->fail_open_delayed_timeout = 150; attachment->sessions_per_minute_limit_verdict = ATTACHMENT_VERDICT_ACCEPT; attachment->max_sessions_per_minute = 0; attachment->req_max_proccessing_ms_time = 3000; attachment->res_max_proccessing_ms_time = 3000; attachment->registration_thread_timeout_msec = 100; attachment->req_start_thread_timeout_msec = 100; attachment->req_header_thread_timeout_msec = 100; attachment->req_body_thread_timeout_msec = 150; attachment->res_header_thread_timeout_msec = 100; attachment->res_body_thread_timeout_msec = 150; attachment->waiting_for_verdict_thread_timeout_msec = 150; attachment->metric_timeout_timeout = 100; attachment->inspection_mode = NON_BLOCKING_THREAD; attachment->num_of_nano_ipc_elements = 200; attachment->keep_alive_interval_msec = DEFAULT_KEEP_ALIVE_INTERVAL_MSEC; if (nano_attachment_init_process(attachment) != NANO_OK) { write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Could not initialize nano attachment"); close_logging_fd(attachment); free(attachment); return NULL; } reset_metric_data(attachment); return attachment; }; void FiniNanoAttachment(NanoAttachment *attachment) { close_logging_fd(attachment); free(attachment); }; NanoCommunicationResult RestartAttachmentConfiguration(NanoAttachment *attachment) { return reset_attachment_config(attachment); }; HttpSessionData * InitSessionData(NanoAttachment *attachment, SessionID session_id) { HttpSessionData *session_data = malloc(sizeof(HttpSessionData)); if (session_data == NULL) { return NULL; } write_dbg( attachment, session_id, DBG_LEVEL_TRACE, "Initiating session data" ); session_data->was_request_fully_inspected = 0; session_data->verdict = TRAFFIC_VERDICT_INSPECT; session_data->session_id = session_id; session_data->remaining_messages_to_reply = 0; session_data->req_proccesing_time = 0; session_data->res_proccesing_time = 0; session_data->processed_req_body_size = 0; session_data->processed_res_body_size = 0; session_data->response_data.compression_type = NO_COMPRESSION; session_data->response_data.compression_stream = NULL; session_data->response_data.decompression_stream = NULL; return session_data; }; void FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_DEBUG, "Freeing session data for session_id" ); if (session_data->response_data.compression_stream != NULL) { finiCompressionStream(session_data->response_data.compression_stream); session_data->response_data.compression_stream = NULL; } if (session_data->response_data.decompression_stream != NULL) { finiCompressionStream(session_data->response_data.decompression_stream); session_data->response_data.decompression_stream = NULL; } free(session_data); }; void UpdateMetric(NanoAttachment *attachment, AttachmentMetricType metric_type, uint64_t value) { updateMetricField(attachment, metric_type, value); } void SendAccumulatedMetricData(NanoAttachment *attachment) { SendMetricData(attachment); } AttachmentVerdictResponse SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data) { switch (data->chunk_type) { case HTTP_REQUEST_FILTER: { return SendRequestFilter(attachment, data); } case HTTP_REQUEST_METADATA: { return SendMetadata(attachment, data); } case HTTP_REQUEST_HEADER: { return SendRequestHeaders(attachment, data); } case HTTP_REQUEST_BODY: { return SendRequestBody(attachment, data); } case HTTP_REQUEST_END: { return SendRequestEnd(attachment, data); } case HTTP_RESPONSE_HEADER: { return SendResponseHeaders(attachment, data); } case HTTP_RESPONSE_BODY: { return SendResponseBody(attachment, data); } case HTTP_RESPONSE_END: { return SendResponseEnd(attachment, data); } default: break; } AttachmentVerdictResponse response = { .verdict = ATTACHMENT_VERDICT_INSPECT, .session_id = data->session_id, .modifications = NULL }; return response; } /// /// @brief Connects to the keep-alive socket. /// /// @param attachment A pointer to a NanoAttachment struct containing attachment information. /// /// @return An int representing an opened socket, if failed returns -1. /// static int connect_to_keep_alive_socket(NanoAttachment *attachment) { struct sockaddr_un server; int keep_alive_socket; // Connect a new socket. keep_alive_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (keep_alive_socket < 0) { write_dbg( attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Could not create socket, Error: %s", strerror(errno) ); return keep_alive_socket; } server.sun_family = AF_UNIX; strncpy(server.sun_path, SHARED_KEEP_ALIVE_PATH, sizeof(server.sun_path) - 1); if (connect(keep_alive_socket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) != -1 ) { return keep_alive_socket; } write_dbg( attachment, attachment->worker_id, DBG_LEVEL_DEBUG, "Could not connect to nano service. Path: %s, Error: %s, Errno: %d", server.sun_path, strerror(errno), errno ); close(keep_alive_socket); return -1; } /// /// @brief Sends the keep-alive signal to the alive socket. /// /// @param attachment A pointer to a NanoAttachment struct containing attachment information. /// @param keep_alive_socket Socket descriptor for the keep-alive socket. /// /// @return A NanoCommunicationResult indicating the result of the communication operation. /// static NanoCommunicationResult send_keep_alive_to_alive_socket(NanoAttachment *attachment, int keep_alive_socket) { uint8_t container_id_size = strlen(attachment->container_id); struct timeval timeout = get_absolute_timeout_val_sec(1); NanoCommunicationResult res; // Exchanging worker id with the nano service. res = write_to_service( attachment, &keep_alive_socket, &attachment->worker_id, sizeof(attachment->worker_id), &timeout ); if (res != NANO_OK) { // Failed to send worker id write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send worker id"); return NANO_ERROR; } // Exchanging container id size with the nano service. res = write_to_service( attachment, &keep_alive_socket, &container_id_size, sizeof(container_id_size), &timeout ); if (res != NANO_OK) { // Failed to send container id size. write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send container id size"); return NANO_ERROR; } if (container_id_size > 0) { // Exchanging container id with the nano service. res = write_to_service( attachment, &keep_alive_socket, attachment->container_id, container_id_size, &timeout ); if (res != NANO_OK) { // Failed to send container id name. write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send container id"); return NANO_ERROR; } } return NANO_OK; } void SendKeepAlive(NanoAttachment *attachment) { int keep_alive_socket; NanoCommunicationResult res; write_dbg( attachment, attachment->worker_id, DBG_LEVEL_DEBUG, "Keep alive signal. Family id: %s, UID: %u", attachment->container_id, attachment->worker_id ); keep_alive_socket = connect_to_keep_alive_socket(attachment); if (keep_alive_socket < 0) { write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to connect to keep alive socket"); return; } write_dbg( attachment, attachment->worker_id, DBG_LEVEL_DEBUG, "connected to socket: %d. sending keep alive signals" ); res = send_keep_alive_to_alive_socket(attachment, keep_alive_socket); if (res == NANO_ERROR) { write_dbg(attachment, attachment->worker_id, DBG_LEVEL_WARNING, "Failed to send keep alive data"); } close(keep_alive_socket); } int IsSessionFinalized(NanoAttachment *attachment, HttpSessionData *session_data) { if (session_data->verdict == TRAFFIC_VERDICT_INSPECT) { write_dbg( attachment, attachment->worker_id, DBG_LEVEL_TRACE, "Inspecting data for session id: %d", session_data->session_id ); return 0; } write_dbg( attachment, attachment->worker_id, DBG_LEVEL_TRACE, "Skipping already inspected for session id: %d", session_data->session_id ); return 1; } NanoWebResponseType GetWebResponseType( NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response ) { if (response->web_response_data == NULL) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_WARNING, "Trying to get web response with no response object" ); return NO_WEB_RESPONSE; } return response->web_response_data->web_response_type; } int IsResponseWithModification( NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response ) { int res = response->modifications != NULL; write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Response %s have modifications", res ? "does" : "does not" ); return res; } NanoResponseModifications GetResponseModifications( NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response ) { if (response == NULL) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_WARNING, "Trying to get modifications with no response object" ); return (NanoResponseModifications) { .modifications = NULL }; } return (NanoResponseModifications) { .modifications = response->modifications }; } BlockPageData GetBlockPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response) { WebResponseData *web_response_data = response->web_response_data; CustomResponseData *custom_response_data; if (web_response_data->web_response_type != CUSTOM_WEB_RESPONSE) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_WARNING, "Trying to generate custom block page with a non custom response object" ); return (BlockPageData) { .response_code = 0, .title_prefix = { .len = 0, .data = NULL }, .title = { .len = 0, .data = NULL }, .body_prefix = { .len = 0, .data = NULL }, .body = { .len = 0, .data = NULL }, .uuid_prefix = { .len = 0, .data = NULL }, .uuid = { .len = 0, .data = NULL }, .uuid_suffix = { .len = 0, .data = NULL } }; } write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Getting custom block page" ); custom_response_data = (CustomResponseData *) web_response_data->data; return (BlockPageData) { .response_code = custom_response_data->response_code, .title_prefix = { .len = strlen(title_prefix), .data = (unsigned char *)title_prefix }, .title = { .len = strlen((char *)custom_response_data->title), .data = custom_response_data->title }, .body_prefix = { .len = strlen(body_prefix), .data = (unsigned char *)body_prefix }, .body = { .len = strlen((char *)custom_response_data->body), .data = custom_response_data->body }, .uuid_prefix = { .len = strlen(uuid_prefix), .data = (unsigned char *)uuid_prefix }, .uuid = { .len = strlen((char *)web_response_data->uuid), .data = web_response_data->uuid }, .uuid_suffix = { .len = strlen(uuid_suffix), .data = (unsigned char *)uuid_suffix } }; } uint16_t GetResponseCode(AttachmentVerdictResponse *response) { WebResponseData *web_response_data = response->web_response_data; CustomResponseData *custom_response_data; custom_response_data = (CustomResponseData *) web_response_data->data; return custom_response_data->response_code; } RedirectPageData GetRedirectPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response) { WebResponseData *web_response_data = response->web_response_data; RedirectData *redirect_data; if (web_response_data->web_response_type != REDIRECT_WEB_RESPONSE) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_WARNING, "Trying to generate custom block page with a non redirect response object" ); return (RedirectPageData) { .redirect_location = { .len = 0, .data = NULL } }; } write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Getting redirect data" ); redirect_data = (RedirectData *) web_response_data->data; return (RedirectPageData) { .redirect_location = { .len = strlen((char*)redirect_data->redirect_location), .data = redirect_data->redirect_location } }; } void FreeAttachmentResponseContent( NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response ) { NanoHttpModificationList *current_modification; NanoHttpModificationList *modification_list; if (response == NULL) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_WARNING, "Attempting to free NULL response" ); return; } write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Freeing AttachmentResponse object" ); if (response->web_response_data != NULL) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Freeing custom web response data" ); free(response->web_response_data->data); free(response->web_response_data); response->web_response_data = NULL; } if (response->modifications != NULL) { modification_list = response->modifications; while (modification_list) { write_dbg( attachment, session_data->session_id, DBG_LEVEL_TRACE, "Freeing modifications list" ); current_modification = modification_list; modification_list = modification_list->next; free(current_modification); } response->modifications = NULL; } return; } HttpBody * compressBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies) { return nano_compress_body(attachment, bodies, session_data); } HttpBody * decompressBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies) { return nano_decompress_body(attachment, bodies, session_data); } void freeCompressedBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies) { nano_free_compressed_body(attachment, bodies, session_data); }