/* Chrysalide - Outil d'analyse de fichiers binaires * packed.c - regroupement de bribes de paquets réseau * * Copyright (C) 2017-2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "packed.h" #include #include #include #include #include "../core/logs.h" /* Taille d'allocation en cas de besoin */ #define PACKET_BLOCK_SIZE 1000 /****************************************************************************** * * * Paramètres : pbuf = paquet de données à initialiser. [OUT] * * * * Description : Initialise un paquet réseau pour une constitution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void init_packed_buffer(packed_buffer_t *pbuf) { pbuf->allocated = PACKET_BLOCK_SIZE; pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t)); reset_packed_buffer(pbuf); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à réinitialiser. [OUT] * * * * Description : Rembobine le paquet de données à son départ. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void rewind_packed_buffer(packed_buffer_t *pbuf) { pbuf->pos = sizeof(uint32_t); assert(pbuf->pos <= pbuf->allocated); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à réinitialiser. [OUT] * * * * Description : Réinitialise un paquet réseau pour une constitution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void reset_packed_buffer(packed_buffer_t *pbuf) { pbuf->used = 0; rewind_packed_buffer(pbuf); assert(pbuf->pos <= pbuf->allocated); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à libérer. * * * * Description : Efface les données contenues par un paquet réseau. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void exit_packed_buffer(packed_buffer_t *pbuf) { #ifndef NDEBUG assert(pbuf->data != NULL); #endif if (pbuf->data) { free(pbuf->data); pbuf->data = NULL; } } /****************************************************************************** * * * Paramètres : dest = tampon de données à constituer. * * src = tampon de données à copier. * * * * Description : Copie les données d'un tampon dans un autre. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void copy_packed_buffer(packed_buffer_t *dest, const packed_buffer_t *src) { size_t len; /* Taille des données à copier */ exit_packed_buffer(dest); len = dest->allocated * sizeof(uint8_t); dest->allocated = src->allocated; dest->data = malloc(len); memcpy(dest->data, src->data, len); dest->used = src->used; dest->pos = src->pos; } /****************************************************************************** * * * Paramètres : dest = tampon de données à constituer. * * src = tampon de données à copier. * * * * Description : Inclut les données d'un tampon dans un autre. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ bool include_packed_buffer(packed_buffer_t *dest, const packed_buffer_t *src) { bool result; /* Bilan à retourner */ assert(src->allocated >= (sizeof(uint32_t) + src->used)); result = extend_packed_buffer(dest, src->data + sizeof(uint32_t), src->used, false); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * * * Description : Indique le nombre d'octets de la charge utile d'un paquet. * * * * Retour : Quantité de données utiles. * * * * Remarques : - * * * ******************************************************************************/ size_t get_packed_buffer_payload_length(const packed_buffer_t *pbuf) { size_t result; /* Quantité à renvoyer */ result = pbuf->used; return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * * * Description : Détermine si des données sont disponibles en lecture. * * * * Retour : true si des données peuvent être dépilées, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool has_more_data_in_packed_buffer(const packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ result = (pbuf->pos < (pbuf->used + sizeof(uint32_t))); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à compléter. * * data = nouvelles données à ajouter. * * len = quantité de ces données. * * hton = indique si une conversion est à réaliser. * * * * Description : Ajoute des données à un paquet en amont à un envoi. * * * * Retour : true. * * * * Remarques : - * * * ******************************************************************************/ bool extend_packed_buffer(packed_buffer_t *pbuf, const void *data, size_t len, bool hton) { uint16_t tmp16; /* Valeur intermédiaire 16b */ uint32_t tmp32; /* Valeur intermédiaire 32b */ uint64_t tmp64; /* Valeur intermédiaire 64b */ /* Réallocation nécessaire ? */ while ((pbuf->pos + len) > pbuf->allocated) { pbuf->allocated += PACKET_BLOCK_SIZE; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } /* Conversion au formalisme du réseau */ if (!hton) goto skip_conversion; switch (len) { case 1: *((uint8_t *)(pbuf->data + pbuf->pos)) = *((uint8_t *)data); break; case 2: tmp16 = htobe16(*(uint16_t *)data); *((uint16_t *)(pbuf->data + pbuf->pos)) = tmp16; break; case 4: tmp32 = htobe32(*(uint32_t *)data); *((uint32_t *)(pbuf->data + pbuf->pos)) = tmp32; break; case 8: tmp64 = htobe64(*(uint64_t *)data); *((uint64_t *)(pbuf->data + pbuf->pos)) = tmp64; break; default: skip_conversion: /** * Dans ce cas de figure, c'est à l'appelant de s'assurer que la * conversion a bien été réalisée. */ assert(!hton); memcpy(pbuf->data + pbuf->pos, data, len); break; } pbuf->used += len; pbuf->pos += len; return true; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * buf = nouvelles données à définir. * * len = quantité de ces données. * * ntoh = indique si une conversion est à réaliser. * * * * Description : Récupère des données depuis un paquet après une réception. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool peek_packed_buffer(packed_buffer_t *pbuf, void *buf, size_t len, bool ntoh) { bool result; /* Bilan à retourner */ uint16_t tmp16; /* Valeur intermédiaire 16b */ uint32_t tmp32; /* Valeur intermédiaire 32b */ uint64_t tmp64; /* Valeur intermédiaire 64b */ result = ((pbuf->pos + len - sizeof(uint32_t)) <= pbuf->used); if (!result) goto failed; /* Conversion au formalisme du réseau */ if (!ntoh) goto skip_conversion; switch (len) { case 1: *((uint8_t *)buf) = *((uint8_t *)(pbuf->data + pbuf->pos)); break; case 2: tmp16 = be16toh(*(uint16_t *)(pbuf->data + pbuf->pos)); *((uint16_t *)buf) = tmp16; break; case 4: tmp32 = be32toh(*(uint32_t *)(pbuf->data + pbuf->pos)); *((uint32_t *)buf) = tmp32; break; case 8: tmp64 = be64toh(*(uint64_t *)(pbuf->data + pbuf->pos)); *((uint64_t *)buf) = tmp64; break; default: skip_conversion: /** * Dans ce cas de figure, c'est à l'appelant de s'assurer que la * conversion a bien été réalisée. */ assert(!ntoh); memcpy(buf, pbuf->data + pbuf->pos, len); break; } failed: return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * len = quantité de ces données. * * * * Description : Avance la tête de lecture dans les données d'un paquet. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void advance_packed_buffer(packed_buffer_t *pbuf, size_t len) { pbuf->pos += len; assert((pbuf->pos - sizeof(uint32_t)) <= pbuf->used); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * buf = nouvelles données à définir. * * len = quantité de ces données. * * ntoh = indique si une conversion est à réaliser. * * * * Description : Récupère des données depuis un paquet après une réception. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool extract_packed_buffer(packed_buffer_t *pbuf, void *buf, size_t len, bool ntoh) { bool result; /* Bilan à retourner */ result = peek_packed_buffer(pbuf, buf, len, ntoh); if (result) advance_packed_buffer(pbuf, len); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à constituer. [OUT] * * fd = flux ouvert en lecture. * * * * Description : Lit des données depuis un flux local. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ result = safe_read(fd, &used, sizeof(uint32_t)); if (result) { assert(pbuf->pos == sizeof(uint32_t)); if ((pbuf->pos + used) > pbuf->allocated) { pbuf->allocated = pbuf->pos + used; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } pbuf->used = used; result = safe_read(fd, pbuf->data + pbuf->pos, used); } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à émettre. * * fd = flux ouvert en écriture. * * * * Description : Ecrit des données dans un flux local. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool write_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ *((uint32_t *)pbuf->data) = pbuf->used; result = safe_write(fd, pbuf->data, sizeof(uint32_t) + pbuf->used); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à constituer. [OUT] * * fd = flux ouvert en lecture. * * * * Description : Réceptionne des données depuis un flux réseau. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool recv_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ result = safe_recv(fd, &used, sizeof(uint32_t), 0); if (result) { assert(pbuf->pos == sizeof(uint32_t)); if ((pbuf->pos + used) > pbuf->allocated) { pbuf->allocated = pbuf->pos + used; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } pbuf->used = used; result = safe_recv(fd, pbuf->data + pbuf->pos, used, 0); } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à émettre. * * fd = flux ouvert en écriture. * * * * Description : Envoie des données au travers un flux réseau. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool send_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ *((uint32_t *)pbuf->data) = pbuf->used; result = safe_send(fd, pbuf->data, sizeof(uint32_t) + pbuf->used, 0); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à constituer. [OUT] * * fd = flux ouvert en lecture. * * * * Description : Réceptionne des données depuis un flux réseau chiffré. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool ssl_recv_packed_buffer(packed_buffer_t *pbuf, SSL *fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ size_t pos; /* Localisation du stockage */ size_t remaining; /* Quantité à lire restante */ size_t got; /* QUantité lue par appel */ int ret; /* Code de retour d'une lecture*/ got = SSL_read(fd, &used, sizeof(uint32_t)); if (got <= 0) LOG_ERROR_OPENSSL; result = (got == sizeof(uint32_t)); if (result) { assert(pbuf->pos == sizeof(uint32_t)); if ((pbuf->pos + used) > pbuf->allocated) { pbuf->allocated = pbuf->pos + used; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } pbuf->used = used; pos = pbuf->pos; remaining = used; while (remaining > 0) { ret = SSL_read_ex(fd, pbuf->data + pos, remaining, &got); if (ret > 0) { pos += got; remaining -= got; } else { LOG_ERROR_OPENSSL; break; } } result = (remaining == 0); } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à émettre. * * fd = flux ouvert en écriture. * * * * Description : Envoie des données au travers un flux réseau chiffré. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool ssl_send_packed_buffer(packed_buffer_t *pbuf, SSL *fd) { bool result; /* Bilan à retourner */ int quantity; /* Nombre de données à traiter */ int sent; /* Quantité de données traitées*/ *((uint32_t *)pbuf->data) = pbuf->used; quantity = sizeof(uint32_t) + pbuf->used; sent = SSL_write(fd, pbuf->data, quantity); if (sent <= 0) LOG_ERROR_OPENSSL; result = (quantity == sent); return result; }