/* * ndpi_serializer.c * * Copyright (C) 2011-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH * * nDPI is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nDPI 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with nDPI. If not, see . * */ #ifdef HAVE_CONFIG_H #include "ndpi_config.h" #endif #include #include #include #include "ndpi_api.h" #include "ndpi_config.h" #include #ifndef WIN32 #include #endif #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ #include #endif /* ********************************** */ static u_int64_t ndpi_htonll(u_int64_t v) { union { u_int32_t lv[2]; u_int64_t llv; } u; u.lv[0] = htonl(v >> 32); u.lv[1] = htonl(v & 0xFFFFFFFFULL); return(u.llv); } /* ********************************** */ static u_int64_t ndpi_ntohll(u_int64_t v) { union { u_int32_t lv[2]; u_int64_t llv; } u; u.llv = v; return((u_int64_t)ntohl(u.lv[0]) << 32) | (u_int64_t)ntohl(u.lv[1]); } /* ********************************** */ static int ndpi_is_number(const char *str, u_int32_t str_len) { int i; for(i = 0; i < str_len; i++) if(!isdigit(str[i])) return(0); return(1); } /* ********************************** */ /* * Escapes a string to be suitable for a JSON value, adding double quotes, and terminating the string with a null byte. * It is recommended to provide a destination buffer (dst) which is as large as double the source buffer (src) at least. * Upon successful return, these functions return the number of characters printed (excluding the null byte used to terminate the string). */ static int ndpi_json_string_escape(const char *src, int src_len, char *dst, int dst_max_len) { char c = 0; int i, j = 0; dst[j++] = '"'; for(i = 0; i < src_len && j < dst_max_len; i++) { c = src[i]; switch (c) { case '\\': case '"': case '/': dst[j++] = '\\'; dst[j++] = c; break; case '\b': dst[j++] = '\\'; dst[j++] = 'b'; break; case '\t': dst[j++] = '\\'; dst[j++] = 't'; break; case '\n': dst[j++] = '\\'; dst[j++] = 'n'; break; case '\f': dst[j++] = '\\'; dst[j++] = 'f'; break; case '\r': dst[j++] = '\\'; dst[j++] = 'r'; break; default: if(c < ' ') ; /* non printable */ else dst[j++] = c; } } dst[j++] = '"'; dst[j+1] = '\0'; return(j); } /* ********************************** */ void ndpi_reset_serializer(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; serializer->status.flags = 0; if(serializer->fmt == ndpi_serialization_format_json) { u_int32_t buff_diff; serializer->status.size_used = 0; buff_diff = serializer->buffer_size - serializer->status.size_used; /* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */ serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, " {}"); } else if(serializer->fmt == ndpi_serialization_format_csv) serializer->status.size_used = 0; else /* ndpi_serialization_format_tlv */ serializer->status.size_used = 2 * sizeof(u_int8_t); } /* ********************************** */ int ndpi_init_serializer_ll(ndpi_serializer *_serializer, ndpi_serialization_format fmt, u_int32_t buffer_size) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memset(serializer, 0, sizeof(ndpi_private_serializer)); serializer->initial_buffer_size = serializer->buffer_size = buffer_size; serializer->buffer = (u_int8_t *) malloc(serializer->buffer_size * sizeof(u_int8_t)); if(serializer->buffer == NULL) return(-1); serializer->fmt = fmt; serializer->buffer[0] = 1; /* version */ serializer->buffer[1] = (u_int8_t) fmt; serializer->csv_separator[0] = ','; serializer->csv_separator[1] = '\0'; ndpi_reset_serializer(_serializer); return(1); } /* ********************************** */ int ndpi_init_serializer(ndpi_serializer *_serializer, ndpi_serialization_format fmt) { return(ndpi_init_serializer_ll(_serializer, fmt, NDPI_SERIALIZER_DEFAULT_BUFFER_SIZE)); } /* ********************************** */ char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer_len) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; char *buf = (char*)serializer->buffer; /* NULL terminate the buffer if there is space available */ if(serializer->buffer_size > serializer->status.size_used) serializer->buffer[serializer->status.size_used] = '\0'; *buffer_len = serializer->status.size_used; if(serializer->fmt == ndpi_serialization_format_json) { while(buf[0] == '\0') buf++, *buffer_len = *buffer_len - 1; } return(buf); } /* ********************************** */ u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer) { return(((ndpi_private_serializer*)_serializer)->status.size_used); } /* ********************************** */ int ndpi_serializer_set_buffer_len(ndpi_serializer *_serializer, u_int32_t l) { ndpi_private_serializer *p = (ndpi_private_serializer*)_serializer; if(p) { if(p->buffer_size <= l) return(-1); /* Invalid size */ p->status.size_used = l; return(0); } return(-2); } /* ********************************** */ void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separator) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; serializer->csv_separator[0] = separator; } /* ********************************** */ void ndpi_term_serializer(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->buffer) { free(serializer->buffer); serializer->buffer_size = 0; serializer->buffer = NULL; } } /* ********************************** */ static inline int ndpi_extend_serializer_buffer(ndpi_serializer *_serializer, u_int32_t min_len) { u_int32_t new_size; void *r; ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(min_len < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) { if(serializer->initial_buffer_size < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) { if(min_len < serializer->initial_buffer_size) min_len = serializer->initial_buffer_size; } else { min_len = NDPI_SERIALIZER_DEFAULT_BUFFER_INCR; } } new_size = serializer->buffer_size + min_len; r = realloc((void *) serializer->buffer, new_size); if(r == NULL) return(-1); serializer->buffer = r; serializer->buffer_size = new_size; return(0); } /* ********************************** */ static inline void ndpi_serialize_single_uint8(ndpi_private_serializer *serializer, u_int8_t s) { u_int8_t v = s; memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int8_t)); serializer->status.size_used += sizeof(u_int8_t); } /* ********************************** */ static inline void ndpi_serialize_single_uint16(ndpi_private_serializer *serializer, u_int16_t s) { u_int16_t v = htons(s); memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int16_t)); serializer->status.size_used += sizeof(u_int16_t); } /* ********************************** */ static inline void ndpi_serialize_single_uint32(ndpi_private_serializer *serializer, u_int32_t s) { u_int32_t v = htonl(s); memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int32_t)); serializer->status.size_used += sizeof(u_int32_t); } /* ********************************** */ static inline void ndpi_serialize_single_uint64(ndpi_private_serializer *serializer, u_int64_t s) { u_int64_t v = ndpi_htonll(s); memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int64_t)); serializer->status.size_used += sizeof(u_int64_t); } /* ********************************** */ /* TODO: fix portability across platforms */ static inline void ndpi_serialize_single_float(ndpi_private_serializer *serializer, float s) { memcpy(&serializer->buffer[serializer->status.size_used], &s, sizeof(s)); serializer->status.size_used += sizeof(float); } /* ********************************** */ static inline void ndpi_serialize_single_string(ndpi_private_serializer *serializer, const char *s, u_int16_t slen) { u_int16_t l = htons(slen); memcpy(&serializer->buffer[serializer->status.size_used], &l, sizeof(u_int16_t)); serializer->status.size_used += sizeof(u_int16_t); if(slen > 0) memcpy(&serializer->buffer[serializer->status.size_used], s, slen); serializer->status.size_used += slen; } /* ********************************** */ static inline void ndpi_deserialize_single_uint8(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int8_t *s) { *s = (*((u_int8_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint16(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int16_t *s) { *s = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint32(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int32_t *s) { *s = ntohl(*((u_int32_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int8(ndpi_private_deserializer *deserializer, u_int32_t offset, int8_t *s) { *s = (*((int8_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int16(ndpi_private_deserializer *deserializer, u_int32_t offset, int16_t *s) { *s = ntohs(*((int16_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int32(ndpi_private_deserializer *deserializer, u_int32_t offset, int32_t *s) { *s = ntohl(*((int32_t *) &deserializer->buffer[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint64(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int64_t *s) { *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer[offset]); } /* ********************************** */ static inline void ndpi_deserialize_single_int64(ndpi_private_deserializer *deserializer, u_int32_t offset, int64_t *s) { *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer[offset]); } /* ********************************** */ /* TODO: fix portability across platforms */ static inline void ndpi_deserialize_single_float(ndpi_private_deserializer *deserializer, u_int32_t offset, float *s) { *s = *(float*)&deserializer->buffer[offset]; } /* ********************************** */ static inline void ndpi_deserialize_single_string(ndpi_private_deserializer *deserializer, u_int32_t offset, ndpi_string *v) { v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); v->str = (char *) &deserializer->buffer[offset + sizeof(u_int16_t)]; } /* ********************************** */ int ndpi_serialize_end_of_record(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */; if(serializer->fmt == ndpi_serialization_format_json) needed += 1; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY)) { serializer->buffer[0] = '['; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "]"); } serializer->status.flags |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR; serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_COMMA; } else { serializer->buffer[serializer->status.size_used++] = ndpi_serialization_end_of_record; } return(0); } /* ********************************** */ static inline void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->status.flags & NDPI_SERIALIZER_STATUS_EOR) { serializer->status.size_used--; /* Remove ']' */ serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_EOR; serializer->buffer[serializer->status.size_used++] = ','; serializer->buffer[serializer->status.size_used++] = '{'; } else { if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) serializer->status.size_used--; /* Remove ']'*/ serializer->status.size_used--; /* Remove '}'*/ if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB; else if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) serializer->buffer[serializer->status.size_used++] = ','; } } /* ********************************** */ static inline void ndpi_serialize_json_post(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; serializer->buffer[serializer->status.size_used++] = '}'; if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) serializer->buffer[serializer->status.size_used++] = ']'; serializer->status.flags |= NDPI_SERIALIZER_STATUS_COMMA; } /* ********************************** */ static inline ndpi_serialization_type ndpi_serialize_key_uint32(ndpi_private_serializer *serializer, u_int32_t key) { ndpi_serialization_type kt; if(key <= 0xff) { ndpi_serialize_single_uint8(serializer, key); kt = ndpi_serialization_uint8; } else if(key <= 0xffff) { ndpi_serialize_single_uint16(serializer, key); kt = ndpi_serialization_uint16; } else { ndpi_serialize_single_uint32(serializer, key); kt = ndpi_serialization_uint32; } return(kt); } /* ********************************** */ int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, u_int32_t key, u_int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 24; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":%u", key, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%u", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); if(value <= 0xff) { ndpi_serialize_single_uint8(serializer, value); type |= ndpi_serialization_uint8; } else if(value <= 0xffff) { ndpi_serialize_single_uint16(serializer, value); type |= ndpi_serialization_uint16; } else { ndpi_serialize_single_uint32(serializer, value); type |= ndpi_serialization_uint32; } serializer->buffer[type_offset] = type; } return(0); } /* ********************************** */ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, u_int32_t key, u_int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int64_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 32; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":%llu", key, (unsigned long long)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%llu", (serializer->status.size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { if(value <= 0xffffffff) { return(ndpi_serialize_uint32_uint32(_serializer, key, value)); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); ndpi_serialize_single_uint64(serializer, value); type |= ndpi_serialization_uint64; serializer->buffer[type_offset] = type; } } return(0); } /* ********************************** */ int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer, u_int32_t key, int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 24; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":%d", key, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%d", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); if(value <= 127 && value >= -128) { ndpi_serialize_single_uint8(serializer, value); type |= ndpi_serialization_int8; } else if(value <= 32767 && value >= -32768) { ndpi_serialize_single_uint16(serializer, value); type |= ndpi_serialization_int16; } else { ndpi_serialize_single_uint32(serializer, value); type |= ndpi_serialization_int32; } serializer->buffer[type_offset] = type; } return(0); } /* ********************************** */ int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer, u_int32_t key, int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(int64_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 32; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":%lld", key, (long long int)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%lld", (serializer->status.size_used > 0) ? serializer->csv_separator : "", (long long int)value); } else { if(value <= 2147483647 && value >= -2147483648) { return(ndpi_serialize_uint32_int32(_serializer, key, value)); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); ndpi_serialize_single_uint64(serializer, value); type |= ndpi_serialization_int64; serializer->buffer[type_offset] = type; } } return(0); } /* ********************************** */ int ndpi_serialize_uint32_float(ndpi_serializer *_serializer, u_int32_t key, float value, const char *format /* e.f. "%.2f" */) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(float); if(serializer->fmt == ndpi_serialization_format_json) needed += 32; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":", key); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s", (serializer->status.size_used > 0) ? serializer->csv_separator : ""); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); ndpi_serialize_single_float(serializer, value); type |= ndpi_serialization_float; serializer->buffer[type_offset] = type; } return(0); } /* ********************************** */ static int ndpi_serialize_uint32_binary(ndpi_serializer *_serializer, u_int32_t key, const char *value, u_int16_t slen) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int16_t) /* len */ + slen; if(serializer->fmt == ndpi_serialization_format_json) needed += 24 + slen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":", key); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += ndpi_json_string_escape(value, slen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%s", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; u_int32_t type_offset = serializer->status.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); ndpi_serialize_single_string(serializer, value, slen); type |= ndpi_serialization_string; serializer->buffer[type_offset] = type; } return(0); } /* ********************************** */ int ndpi_serialize_uint32_string(ndpi_serializer *_serializer, u_int32_t key, const char *_value) { const char *value = _value ? _value : ""; return(ndpi_serialize_uint32_binary(_serializer, key, value, strlen(value))); } /* ********************************** */ static int ndpi_serialize_binary_int32(ndpi_serializer *_serializer, const char *key, u_int16_t klen, int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_int32(_serializer, atoi(key), value)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":%d", value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%d", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { if(value <= 127 && value >= -128) { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int8; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint8(serializer, value); } else if(value <= 32767 && value >= -32768) { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int16; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint16(serializer, value); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int32; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } } return(0); } /* ********************************** */ int ndpi_serialize_string_int32(ndpi_serializer *_serializer, const char *key, int32_t value) { return(ndpi_serialize_binary_int32(_serializer, key, strlen(key), value)); } /* ********************************** */ int ndpi_serialize_binary_int64(ndpi_serializer *_serializer, const char *key, u_int16_t klen, int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_int64(_serializer, atoi(key), value)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":%lld", (long long int)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%lld", (serializer->status.size_used > 0) ? serializer->csv_separator : "", (long long int)value); } else { if(value <= 2147483647 && value >= -2147483648) { return(ndpi_serialize_string_int32(_serializer, key, value)); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int64; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } } return(0); } /* ********************************** */ int ndpi_serialize_string_int64(ndpi_serializer *_serializer, const char *key, int64_t value) { return(ndpi_serialize_binary_int64(_serializer, key, strlen(key), value)); } /* ********************************** */ static int ndpi_serialize_binary_uint32(ndpi_serializer *_serializer, const char *key, u_int16_t klen, u_int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_uint32(_serializer, atoi(key), value)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":%u", value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%u", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { if(value <= 0xff) { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint8; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint8(serializer, value); } else if(value <= 0xffff) { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint16; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint16(serializer, value); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint32; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } } return(0); } /* ********************************** */ int ndpi_serialize_string_uint32(ndpi_serializer *_serializer, const char *key, u_int32_t value) { return(ndpi_serialize_binary_uint32(_serializer, key, strlen(key), value)); } /* ********************************** */ int ndpi_serialize_string_uint32_format(ndpi_serializer *_serializer, const char *key, u_int32_t value, const char *format) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->fmt == ndpi_serialization_format_json) { /* JSON supports base 10 numbers only http://cjihrig.com/blog/json-overview/ */ return(ndpi_serialize_string_uint32(_serializer, key, value)); } else return(ndpi_serialize_string_uint32_format(_serializer, key, value, format)); } /* ********************************** */ static int ndpi_serialize_binary_uint64(ndpi_serializer *_serializer, const char *key, u_int16_t klen, u_int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_uint64(_serializer, atoi(key), value)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int64_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 32 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":%llu", (unsigned long long)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%llu", (serializer->status.size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { if(value <= 0xffffffff) { return(ndpi_serialize_string_uint32(_serializer, key, value)); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint64; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint64(serializer, value); } } return(0); } /* ********************************** */ int ndpi_serialize_string_uint64(ndpi_serializer *_serializer, const char *key, u_int64_t value) { return(ndpi_serialize_binary_uint64(_serializer, key, strlen(key), value)); } /* ********************************** */ static int ndpi_serialize_binary_float(ndpi_serializer *_serializer, const char *key, u_int16_t klen, float value, const char *format /* e.f. "%.2f" */) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_float(_serializer, atoi(key), value, format)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(float); if(serializer->fmt == ndpi_serialization_format_json) needed += 32 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->buffer[serializer->status.size_used] = ':'; serializer->status.size_used++; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { if(serializer->status.size_used > 0) serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s", serializer->csv_separator); serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_float; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_float(serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_float(ndpi_serializer *_serializer, const char *key, float value, const char *format /* e.f. "%.2f" */) { return(ndpi_serialize_binary_float(_serializer, key, strlen(key), value, format)); } /* ********************************** */ static int ndpi_serialize_binary_binary(ndpi_serializer *_serializer, const char *key, u_int16_t klen, const char *_value, u_int16_t vlen) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; const char *value = _value ? _value : ""; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) return(ndpi_serialize_uint32_string(_serializer, atoi(key), _value)); needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen + sizeof(u_int16_t) /* len */ + vlen; if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen + vlen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":"); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += ndpi_json_string_escape(value, vlen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s%s", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_string; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_string(serializer, value, vlen); } return(0); } /* ********************************** */ int ndpi_serialize_string_binary(ndpi_serializer *_serializer, const char *key, const char *_value, u_int16_t vlen) { return(ndpi_serialize_binary_binary(_serializer, key, strlen(key), _value, vlen)); } /* ********************************** */ int ndpi_serialize_string_string(ndpi_serializer *_serializer, const char *key, const char *_value) { return(ndpi_serialize_binary_binary(_serializer, key, strlen(key), _value, strlen(_value))); } /* ********************************** */ /* Serialize start of nested block (JSON only)*/ int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, const char *key) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed, klen = strlen(key); if(serializer->fmt != ndpi_serialization_format_json) return(-1); needed = 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } ndpi_serialize_json_pre(_serializer); serializer->status.size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->status.size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->status.size_used; serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ": {"); buff_diff = serializer->buffer_size - serializer->status.size_used; ndpi_serialize_json_post(_serializer); serializer->status.flags |= NDPI_SERIALIZER_STATUS_SOB; return(0); } /* ********************************** */ /* Serialize start of nested block (JSON only)*/ int ndpi_serialize_end_of_block(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; u_int32_t needed; if(serializer->fmt != ndpi_serialization_format_json) return(-1); needed = 4; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->status.size_used; } // buff_diff = serializer->buffer_size - serializer->status.size_used; ndpi_serialize_json_post(_serializer); return(0); } /* ********************************** */ void ndpi_serializer_create_snapshot(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; #if 0 printf("[NDPI] Snapshot status: %s%s%s\n", (serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) ? " COMMA" : "", (serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) ? " ARRAY" : "", (serializer->status.flags & NDPI_SERIALIZER_STATUS_EOR) ? " EOR" : "" ); #endif memcpy(&serializer->snapshot, &serializer->status, sizeof(ndpi_private_serializer_status)); serializer->has_snapshot = 1; } /* ********************************** */ void ndpi_serializer_rollback_snapshot(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->has_snapshot) { memcpy(&serializer->status, &serializer->snapshot, sizeof(ndpi_private_serializer_status)); serializer->has_snapshot = 0; if(serializer->fmt == ndpi_serialization_format_json) { if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) { serializer->buffer[serializer->status.size_used-1] = ']'; } else { serializer->buffer[0] = ' '; serializer->buffer[serializer->status.size_used-1] = '}'; } } } } /* ********************************** */ /* ********************************** */ int ndpi_init_deserializer_buf(ndpi_deserializer *_deserializer, u_int8_t *serialized_buffer, u_int32_t serialized_buffer_len) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(serialized_buffer_len < (2 * sizeof(u_int8_t))) return(-1); deserializer->buffer = serialized_buffer; if(deserializer->buffer[0] != 1) return(-2); /* Invalid version */ deserializer->buffer_size = serialized_buffer_len; deserializer->fmt = deserializer->buffer[1]; ndpi_reset_serializer(_deserializer); return(0); } /* ********************************** */ int ndpi_init_deserializer(ndpi_deserializer *deserializer, ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; return(ndpi_init_deserializer_buf(deserializer, serializer->buffer, serializer->status.size_used)); } /* ********************************** */ ndpi_serialization_format ndpi_deserialize_get_format(ndpi_deserializer *_deserializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; return(deserializer->fmt); } /* ********************************** */ static inline ndpi_serialization_type ndpi_deserialize_get_key_subtype(ndpi_private_deserializer *deserializer) { u_int8_t type; if(deserializer->status.size_used >= deserializer->buffer_size) return(ndpi_serialization_unknown); type = deserializer->buffer[deserializer->status.size_used]; return((ndpi_serialization_type) (type >> 4)); } /* ********************************** */ static inline ndpi_serialization_type ndpi_deserialize_get_value_subtype(ndpi_private_deserializer *deserializer) { u_int8_t type; if(deserializer->status.size_used >= deserializer->buffer_size) return(ndpi_serialization_unknown); type = deserializer->buffer[deserializer->status.size_used]; return(ndpi_serialization_type) (type & 0xf); } /* ********************************** */ ndpi_serialization_type ndpi_deserialize_get_item_type(ndpi_deserializer *_deserializer, ndpi_serialization_type *key_type) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; /* Note: 32/64 bit types are automatically encoded/decoded as 8/16 bit */ kt = ndpi_deserialize_get_key_subtype(deserializer); switch(kt) { case ndpi_serialization_uint8: case ndpi_serialization_uint16: kt = ndpi_serialization_uint32; break; default: break; } et = ndpi_deserialize_get_value_subtype(deserializer); switch(et) { case ndpi_serialization_uint8: case ndpi_serialization_uint16: et = ndpi_serialization_uint32; break; case ndpi_serialization_int8: case ndpi_serialization_int16: et = ndpi_serialization_int32; break; default: break; } *key_type = kt; return(et); } /* ********************************** */ static inline int ndpi_deserialize_get_single_string_size(ndpi_private_deserializer *deserializer, u_int32_t offset) { u_int32_t buff_diff = deserializer->buffer_size - offset; u_int16_t expected, str_len; expected = sizeof(u_int16_t) /* len */; if(buff_diff < expected) return(-2); str_len = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); expected += str_len; if(buff_diff < expected) return(-2); return(expected); } /* ********************************** */ static inline int ndpi_deserialize_get_single_size(ndpi_private_deserializer *deserializer, ndpi_serialization_type type, u_int32_t offset) { u_int16_t size; switch(type) { case ndpi_serialization_uint8: case ndpi_serialization_int8: size = sizeof(u_int8_t); break; case ndpi_serialization_uint16: case ndpi_serialization_int16: size = sizeof(u_int16_t); break; case ndpi_serialization_uint32: case ndpi_serialization_int32: size = sizeof(u_int32_t); break; case ndpi_serialization_uint64: case ndpi_serialization_int64: size = sizeof(u_int64_t); break; case ndpi_serialization_float: size = sizeof(float); break; case ndpi_serialization_string: size = ndpi_deserialize_get_single_string_size(deserializer, offset); break; case ndpi_serialization_end_of_record: case ndpi_serialization_unknown: size = 0; break; default: return(-2); break; } return(size); } /* ********************************** */ int ndpi_deserialize_next(ndpi_deserializer *_deserializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; ndpi_serialization_type kt, et; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; deserializer->status.size_used += expected; return(0); } /* ********************************** */ int ndpi_deserialize_key_uint32(ndpi_deserializer *_deserializer, u_int32_t *key) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; ndpi_serialization_type kt; u_int16_t expected; u_int16_t v16; u_int8_t v8; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); offset = deserializer->status.size_used + expected; switch(kt) { case ndpi_serialization_uint32: ndpi_deserialize_single_uint32(deserializer, offset, key); break; case ndpi_serialization_uint16: ndpi_deserialize_single_uint16(deserializer, offset, &v16); *key = v16; break; case ndpi_serialization_uint8: ndpi_deserialize_single_uint8(deserializer, offset, &v8); *key = v8; break; default: return(-1); break; } return(0); } /* ********************************** */ int ndpi_deserialize_key_string(ndpi_deserializer *_deserializer, ndpi_string *key) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); ndpi_deserialize_single_string(deserializer, deserializer->status.size_used + expected, key); return(0); } /* ********************************** */ int ndpi_deserialize_value_uint32(ndpi_deserializer *_deserializer, u_int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int16_t v16; u_int8_t v8; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); offset = deserializer->status.size_used + expected; switch(et) { case ndpi_serialization_uint32: ndpi_deserialize_single_uint32(deserializer, offset, value); break; case ndpi_serialization_uint16: ndpi_deserialize_single_uint16(deserializer, offset, &v16); *value = v16; break; case ndpi_serialization_uint8: ndpi_deserialize_single_uint8(deserializer, offset, &v8); *value = v8; break; default: break; } return(0); } /* ********************************** */ int ndpi_deserialize_value_uint64(ndpi_deserializer *_deserializer, u_int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int32_t v32; u_int16_t expected; int size; int rc; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_uint64) { /* Try with smaller uint types */ rc = ndpi_deserialize_value_uint32(_deserializer, &v32); *value = v32; return(rc); } ndpi_deserialize_single_uint64(deserializer, deserializer->status.size_used + expected, value); return(0); } /* ********************************** */ int ndpi_deserialize_value_int32(ndpi_deserializer *_deserializer, int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; int16_t v16; int8_t v8; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); offset = deserializer->status.size_used + expected; switch(et) { case ndpi_serialization_int32: ndpi_deserialize_single_int32(deserializer, offset, value); break; case ndpi_serialization_int16: ndpi_deserialize_single_int16(deserializer, offset, &v16); *value = v16; break; case ndpi_serialization_int8: ndpi_deserialize_single_int8(deserializer, offset, &v8); *value = v8; break; default: break; } return(0); } /* ********************************** */ int ndpi_deserialize_value_int64(ndpi_deserializer *_deserializer, int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; int32_t v32; u_int16_t expected; int size; int rc; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_int64) { /* Try with smaller int types */ rc = ndpi_deserialize_value_int32(_deserializer, &v32); *value = v32; return(rc); } ndpi_deserialize_single_int64(deserializer, deserializer->status.size_used + expected, value); return(0); } /* ********************************** */ int ndpi_deserialize_value_float(ndpi_deserializer *_deserializer, float *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_float) return(-1); ndpi_deserialize_single_float(deserializer, deserializer->status.size_used + expected, value); return(0); } /* ********************************** */ int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer, ndpi_string *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int16_t expected; int size; expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_string) return(-1); ndpi_deserialize_single_string(deserializer, deserializer->status.size_used + expected, value); return(0); } /* ********************************** */ /* Clone (with memcpy) the current item in deserializer to serializer (TLV only) */ int ndpi_deserialize_clone_item(ndpi_deserializer *_deserializer, ndpi_serializer *_serializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer; ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t src_buff_diff = deserializer->buffer_size - deserializer->status.size_used; u_int32_t dst_buff_diff = serializer->buffer_size - serializer->status.size_used; ndpi_serialization_type kt, et; u_int16_t expected; int size; if(serializer->fmt != ndpi_serialization_format_tlv) return(-3); expected = sizeof(u_int8_t) /* type */; if(src_buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); if(size < 0) return(-2); expected += size; if(dst_buff_diff < expected) { if(ndpi_extend_serializer_buffer(_serializer, expected - dst_buff_diff) < 0) return(-1); dst_buff_diff = serializer->buffer_size - serializer->status.size_used; } memcpy(&serializer->buffer[serializer->status.size_used], &deserializer->buffer[deserializer->status.size_used], expected); serializer->status.size_used += expected; return(0); } /* ********************************** */ /* Clone all elements in deserializer to serializer (this can be used to convert a TLV record to JSON) */ int ndpi_deserialize_clone_all(ndpi_deserializer *deserializer, ndpi_serializer *serializer) { ndpi_serialization_type kt, et; u_int32_t u32, k32; int32_t i32; u_int64_t u64; int64_t i64; float f; ndpi_string vs, ks; int key_is_string; while((et = ndpi_deserialize_get_item_type(deserializer, &kt)) != ndpi_serialization_unknown) { if(et == ndpi_serialization_end_of_record) { ndpi_serialize_end_of_record(serializer); ndpi_deserialize_next(deserializer); continue; } key_is_string = 0; switch(kt) { case ndpi_serialization_uint32: ndpi_deserialize_key_uint32(deserializer, &k32); break; case ndpi_serialization_string: ndpi_deserialize_key_string(deserializer, &ks); key_is_string = 1; break; default: return(-1); } switch(et) { case ndpi_serialization_uint32: ndpi_deserialize_value_uint32(deserializer, &u32); if(key_is_string) ndpi_serialize_binary_uint32(serializer, ks.str, ks.str_len, u32); else ndpi_serialize_uint32_uint32(serializer, k32, u32); break; case ndpi_serialization_uint64: ndpi_deserialize_value_uint64(deserializer, &u64); if(key_is_string) ndpi_serialize_binary_uint64(serializer, ks.str, ks.str_len, u64); else ndpi_serialize_uint32_uint64(serializer, k32, u64); break; case ndpi_serialization_int32: ndpi_deserialize_value_int32(deserializer, &i32); if(key_is_string) ndpi_serialize_binary_int32(serializer, ks.str, ks.str_len, i32); else ndpi_serialize_uint32_int32(serializer, k32, i32); break; case ndpi_serialization_int64: ndpi_deserialize_value_int64(deserializer, &i64); if(key_is_string) ndpi_serialize_binary_int64(serializer, ks.str, ks.str_len, i64); else ndpi_serialize_uint32_int64(serializer, k32, i64); break; case ndpi_serialization_float: ndpi_deserialize_value_float(deserializer, &f); if(key_is_string) ndpi_serialize_binary_float(serializer, ks.str, ks.str_len, f, "%.3f"); else ndpi_serialize_uint32_float(serializer, k32, f, "%.3f"); break; case ndpi_serialization_string: ndpi_deserialize_value_string(deserializer, &vs); if(key_is_string) ndpi_serialize_binary_binary(serializer, ks.str, ks.str_len, vs.str, vs.str_len); else ndpi_serialize_uint32_binary(serializer, k32, vs.str, vs.str_len); break; default: return(-2); } ndpi_deserialize_next(deserializer); } return(0); } /* ********************************** */