/*
* ndpi_utils.c
*
* Copyright (C) 2011-21 - 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 .
*
*/
#include
#include
#include
#include
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN
#include "ndpi_config.h"
#include "ndpi_api.h"
#include "ndpi_includes.h"
#include "ndpi_encryption.h"
#include "ahocorasick.h"
#include "libcache.h"
#include
#ifndef WIN32
#include
#endif
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
#include
#endif
#include "third_party/include/ndpi_patricia.h"
#include "third_party/include/libinjection.h"
#include "third_party/include/libinjection_sqli.h"
#include "third_party/include/libinjection_xss.h"
#include "third_party/include/rce_injection.h"
#define NDPI_CONST_GENERIC_PROTOCOL_NAME "GenericProtocol"
// #define MATCH_DEBUG 1
// #define DEBUG_REASSEMBLY
/* ****************************************** */
/* implementation of the punycode check function */
int ndpi_check_punycode_string(char * buffer , int len) {
int i = 0;
while(i++ < len) {
if((buffer[i] == 'x')
&& (buffer[i+1] == 'n')
&& (buffer[i+2] == '-')
&& (buffer[i+3] == '-'))
// is a punycode string
return(1);
}
// not a punycode string
return 0;
}
/* ****************************************** */
/* ftp://ftp.cc.uoc.gr/mirrors/OpenBSD/src/lib/libc/stdlib/tsearch.c */
/* find or insert datum into search tree */
void * ndpi_tsearch(const void *vkey, void **vrootp,
int (*compar)(const void *, const void *))
{
ndpi_node *q;
char *key = (char *)vkey;
ndpi_node **rootp = (ndpi_node **)vrootp;
if(rootp == (ndpi_node **)0)
return ((void *)0);
while (*rootp != (ndpi_node *)0) { /* Knuth's T1: */
int r;
if((r = (*compar)(key, (*rootp)->key)) == 0) /* T2: */
return ((*rootp)->key); /* we found it! */
rootp = (r < 0) ?
&(*rootp)->left : /* T3: follow left branch */
&(*rootp)->right; /* T4: follow right branch */
}
q = (ndpi_node *) ndpi_malloc(sizeof(ndpi_node)); /* T5: key not found */
if(q != (ndpi_node *)0) { /* make new node */
*rootp = q; /* link new node to old */
q->key = key; /* initialize new node */
q->left = q->right = (ndpi_node *)0;
}
return ((void *)q->key);
}
/* ****************************************** */
/* delete node with given key */
void * ndpi_tdelete(const void *vkey, void **vrootp,
int (*compar)(const void *, const void *))
{
ndpi_node **rootp = (ndpi_node **)vrootp;
char *key = (char *)vkey;
ndpi_node *q;
ndpi_node *r;
int cmp;
if(rootp == (ndpi_node **)0 || *rootp == (ndpi_node *)0)
return((void *)0);
while ((cmp = (*compar)(key, (*rootp)->key)) != 0) {
rootp = (cmp < 0) ?
&(*rootp)->left : /* follow left branch */
&(*rootp)->right; /* follow right branch */
if(*rootp == (ndpi_node *)0)
return ((void *)0); /* key not found */
}
r = (*rootp)->right; /* D1: */
if((q = (*rootp)->left) == (ndpi_node *)0) /* Left (ndpi_node *)0? */
q = r;
else if(r != (ndpi_node *)0) { /* Right link is null? */
if(r->left == (ndpi_node *)0) { /* D2: Find successor */
r->left = q;
q = r;
} else { /* D3: Find (ndpi_node *)0 link */
for(q = r->left; q->left != (ndpi_node *)0; q = r->left)
r = q;
r->left = q->right;
q->left = (*rootp)->left;
q->right = (*rootp)->right;
}
}
key = (*rootp)->key;
ndpi_free((ndpi_node *) *rootp); /* D4: Free node */
*rootp = q; /* link parent to new node */
/* Return the key to give the caller a chance to free custom data */
return(key);
}
/* ****************************************** */
/* Walk the nodes of a tree */
static void ndpi_trecurse(ndpi_node *root, void (*action)(const void *, ndpi_VISIT, int, void*), int level, void *user_data)
{
if(root->left == (ndpi_node *)0 && root->right == (ndpi_node *)0)
(*action)(root, ndpi_leaf, level, user_data);
else {
(*action)(root, ndpi_preorder, level, user_data);
if(root->left != (ndpi_node *)0)
ndpi_trecurse(root->left, action, level + 1, user_data);
(*action)(root, ndpi_postorder, level, user_data);
if(root->right != (ndpi_node *)0)
ndpi_trecurse(root->right, action, level + 1, user_data);
(*action)(root, ndpi_endorder, level, user_data);
}
}
/* ****************************************** */
/* Walk the nodes of a tree */
void ndpi_twalk(const void *vroot, void (*action)(const void *, ndpi_VISIT, int, void *), void *user_data)
{
ndpi_node *root = (ndpi_node *)vroot;
if(root != (ndpi_node *)0 && action != (void (*)(const void *, ndpi_VISIT, int, void*))0)
ndpi_trecurse(root, action, 0, user_data);
}
/* ****************************************** */
/* find a node, or return 0 */
void * ndpi_tfind(const void *vkey, void *vrootp,
int (*compar)(const void *, const void *))
{
char *key = (char *)vkey;
ndpi_node **rootp = (ndpi_node **)vrootp;
if(rootp == (ndpi_node **)0)
return ((ndpi_node *)0);
while (*rootp != (ndpi_node *)0) { /* T1: */
int r;
if((r = (*compar)(key, (*rootp)->key)) == 0) /* T2: */
return (*rootp); /* key found */
rootp = (r < 0) ?
&(*rootp)->left : /* T3: follow left branch */
&(*rootp)->right; /* T4: follow right branch */
}
return (ndpi_node *)0;
}
/* ****************************************** */
/* Walk the nodes of a tree */
static void ndpi_tdestroy_recurse(ndpi_node* root, void (*free_action)(void *))
{
if(root->left != NULL)
ndpi_tdestroy_recurse(root->left, free_action);
if(root->right != NULL)
ndpi_tdestroy_recurse(root->right, free_action);
(*free_action) ((void *) root->key);
ndpi_free(root);
}
void ndpi_tdestroy(void *vrootp, void (*freefct)(void *))
{
ndpi_node *root = (ndpi_node *) vrootp;
if(root != NULL)
ndpi_tdestroy_recurse(root, freefct);
}
/* ****************************************** */
u_int8_t ndpi_net_match(u_int32_t ip_to_check,
u_int32_t net,
u_int32_t num_bits) {
u_int32_t mask = 0;
num_bits &= 0x1F; /* Avoid overflows */
mask = ~(~mask >> num_bits);
return(((ip_to_check & mask) == (net & mask)) ? 1 : 0);
}
u_int8_t ndpi_ips_match(u_int32_t src, u_int32_t dst,
u_int32_t net, u_int32_t num_bits)
{
return(ndpi_net_match(src, net, num_bits) || ndpi_net_match(dst, net, num_bits));
}
/* ****************************************** */
#if defined(WIN32) && !defined(__MINGW32__)
/* http://opensource.apple.com/source/Libc/Libc-186/string.subproj/strcasecmp.c */
/*
* This array is designed for mapping upper and lower case letter
* together for a case independent comparison. The mappings are
* based upon ascii character sequences.
*/
static const u_char charmap[] = {
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};
int strcasecmp(const char *s1, const char *s2) {
register const u_char *cm = charmap,
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
while (cm[*us1] == cm[*us2++])
if(*us1++ == '\0')
return (0);
return (cm[*us1] - cm[*--us2]);
}
/* ****************************************** */
int strncasecmp(const char *s1, const char *s2, size_t n) {
if(n != 0) {
register const u_char *cm = charmap,
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
do {
if(cm[*us1] != cm[*us2++])
return (cm[*us1] - cm[*--us2]);
if(*us1++ == '\0')
break;
} while (--n != 0);
}
return (0);
}
#endif
/* **************************************** */
u_int8_t ndpi_is_safe_ssl_cipher(u_int32_t cipher) {
/* https://community.qualys.com/thread/18212-how-does-qualys-determine-the-server-cipher-suites */
switch(cipher) {
/* INSECURE */
case TLS_ECDHE_RSA_WITH_RC4_128_SHA: return(NDPI_CIPHER_INSECURE);
case TLS_RSA_WITH_RC4_128_SHA: return(NDPI_CIPHER_INSECURE);
case TLS_RSA_WITH_RC4_128_MD5: return(NDPI_CIPHER_INSECURE);
/* WEAK */
case TLS_RSA_WITH_AES_256_GCM_SHA384: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_AES_256_CBC_SHA256: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_AES_256_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_AES_128_GCM_SHA256: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_AES_128_CBC_SHA256: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_AES_128_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_3DES_EDE_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_SEED_CBC_SHA: return(NDPI_CIPHER_WEAK);
case TLS_RSA_WITH_IDEA_CBC_SHA: return(NDPI_CIPHER_WEAK);
default:
return(NDPI_CIPHER_SAFE);
}
}
/* ***************************************************** */
const char* ndpi_cipher2str(u_int32_t cipher) {
switch(cipher) {
case TLS_NULL_WITH_NULL_NULL: return("TLS_NULL_WITH_NULL_NULL");
case TLS_RSA_EXPORT_WITH_RC4_40_MD5: return("TLS_RSA_EXPORT_WITH_RC4_40_MD5");
case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: return("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5");
case TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: return("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
case TLS_RSA_WITH_NULL_MD5: return("TLS_RSA_WITH_NULL_MD5");
case TLS_RSA_WITH_NULL_SHA: return("TLS_RSA_WITH_NULL_SHA");
case TLS_RSA_WITH_NULL_SHA256: return("TLS_RSA_WITH_NULL_SHA256");
case TLS_RSA_WITH_RC4_128_MD5: return("TLS_RSA_WITH_RC4_128_MD5");
case TLS_RSA_WITH_RC4_128_SHA: return("TLS_RSA_WITH_RC4_128_SHA");
case TLS_RSA_WITH_IDEA_CBC_SHA: return("TLS_RSA_WITH_IDEA_CBC_SHA");
case TLS_RSA_WITH_DES_CBC_SHA: return("TLS_RSA_WITH_DES_CBC_SHA");
case TLS_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_RSA_WITH_AES_128_CBC_SHA: return("TLS_RSA_WITH_AES_128_CBC_SHA");
case TLS_RSA_WITH_AES_256_CBC_SHA: return("TLS_RSA_WITH_AES_256_CBC_SHA");
case TLS_RSA_WITH_AES_128_CBC_SHA256: return("TLS_RSA_WITH_AES_128_CBC_SHA256");
case TLS_RSA_WITH_AES_256_CBC_SHA256: return("TLS_RSA_WITH_AES_256_CBC_SHA256");
case TLS_RSA_WITH_AES_128_GCM_SHA256: return("TLS_RSA_WITH_AES_128_GCM_SHA256");
case TLS_RSA_WITH_AES_256_GCM_SHA384: return("TLS_RSA_WITH_AES_256_GCM_SHA384");
case TLS_RSA_WITH_AES_128_CCM: return("TLS_RSA_WITH_AES_128_CCM");
case TLS_RSA_WITH_AES_256_CCM: return("TLS_RSA_WITH_AES_256_CCM");
case TLS_RSA_WITH_AES_128_CCM_8: return("TLS_RSA_WITH_AES_128_CCM_8");
case TLS_RSA_WITH_AES_256_CCM_8: return("TLS_RSA_WITH_AES_256_CCM_8");
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: return("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA");
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: return("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA");
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_RSA_WITH_SEED_CBC_SHA: return("TLS_RSA_WITH_SEED_CBC_SHA");
case TLS_RSA_WITH_ARIA_128_CBC_SHA256: return("TLS_RSA_WITH_ARIA_128_CBC_SHA256");
case TLS_RSA_WITH_ARIA_256_CBC_SHA384: return("TLS_RSA_WITH_ARIA_256_CBC_SHA384");
case TLS_RSA_WITH_ARIA_128_GCM_SHA256: return("TLS_RSA_WITH_ARIA_128_GCM_SHA256");
case TLS_RSA_WITH_ARIA_256_GCM_SHA384: return("TLS_RSA_WITH_ARIA_256_GCM_SHA384");
case TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: return("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
case TLS_DH_RSA_WITH_DES_CBC_SHA: return("TLS_DH_RSA_WITH_DES_CBC_SHA");
case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_DH_RSA_WITH_AES_128_CBC_SHA: return("TLS_DH_RSA_WITH_AES_128_CBC_SHA");
case TLS_DH_RSA_WITH_AES_256_CBC_SHA: return("TLS_DH_RSA_WITH_AES_256_CBC_SHA");
case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: return("TLS_DH_RSA_WITH_AES_128_CBC_SHA256");
case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: return("TLS_DH_RSA_WITH_AES_256_CBC_SHA256");
case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: return("TLS_DH_RSA_WITH_AES_128_GCM_SHA256");
case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: return("TLS_DH_RSA_WITH_AES_256_GCM_SHA384");
case TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: return("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA");
case TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: return("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA");
case TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DH_RSA_WITH_SEED_CBC_SHA: return("TLS_DH_RSA_WITH_SEED_CBC_SHA");
case TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256: return("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256");
case TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384: return("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384");
case TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256: return("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256");
case TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384: return("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384");
case TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: return("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
case TLS_DHE_RSA_WITH_DES_CBC_SHA: return("TLS_DHE_RSA_WITH_DES_CBC_SHA");
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: return("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: return("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: return("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256");
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256");
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: return("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256");
case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: return("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384");
case TLS_DHE_RSA_WITH_AES_128_CCM: return("TLS_DHE_RSA_WITH_AES_128_CCM");
case TLS_DHE_RSA_WITH_AES_256_CCM: return("TLS_DHE_RSA_WITH_AES_256_CCM");
case TLS_DHE_RSA_WITH_AES_128_CCM_8: return("TLS_DHE_RSA_WITH_AES_128_CCM_8");
case TLS_DHE_RSA_WITH_AES_256_CCM_8: return("TLS_DHE_RSA_WITH_AES_256_CCM_8");
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: return("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA");
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: return("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA");
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DHE_RSA_WITH_SEED_CBC_SHA: return("TLS_DHE_RSA_WITH_SEED_CBC_SHA");
case TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256: return("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256");
case TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384: return("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384");
case TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256: return("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256");
case TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384: return("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384");
case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: return("TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256");
case TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: return("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
case TLS_DH_DSS_WITH_DES_CBC_SHA: return("TLS_DH_DSS_WITH_DES_CBC_SHA");
case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: return("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA");
case TLS_DH_DSS_WITH_AES_128_CBC_SHA: return("TLS_DH_DSS_WITH_AES_128_CBC_SHA");
case TLS_DH_DSS_WITH_AES_256_CBC_SHA: return("TLS_DH_DSS_WITH_AES_256_CBC_SHA");
case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: return("TLS_DH_DSS_WITH_AES_128_CBC_SHA256");
case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: return("TLS_DH_DSS_WITH_AES_256_CBC_SHA256");
case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: return("TLS_DH_DSS_WITH_AES_128_GCM_SHA256");
case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: return("TLS_DH_DSS_WITH_AES_256_GCM_SHA384");
case TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: return("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA");
case TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: return("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA");
case TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DH_DSS_WITH_SEED_CBC_SHA: return("TLS_DH_DSS_WITH_SEED_CBC_SHA");
case TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256: return("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256");
case TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384: return("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384");
case TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256: return("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256");
case TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384: return("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384");
case TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: return("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
case TLS_DHE_DSS_WITH_DES_CBC_SHA: return("TLS_DHE_DSS_WITH_DES_CBC_SHA");
case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: return("TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: return("TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: return("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256");
case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256");
case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: return("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256");
case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: return("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384");
case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: return("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA");
case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: return("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA");
case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DHE_DSS_WITH_SEED_CBC_SHA: return("TLS_DHE_DSS_WITH_SEED_CBC_SHA");
case TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256: return("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256");
case TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384: return("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384");
case TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256: return("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256");
case TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384: return("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384");
case TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5: return("TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5");
case TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA: return("TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA");
case TLS_DH_ANON_WITH_RC4_128_MD5: return("TLS_DH_ANON_WITH_RC4_128_MD5");
case TLS_DH_ANON_WITH_DES_CBC_SHA: return("TLS_DH_ANON_WITH_DES_CBC_SHA");
case TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA: return("TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA");
case TLS_DH_ANON_WITH_AES_128_CBC_SHA: return("TLS_DH_ANON_WITH_AES_128_CBC_SHA");
case TLS_DH_ANON_WITH_AES_256_CBC_SHA: return("TLS_DH_ANON_WITH_AES_256_CBC_SHA");
case TLS_DH_ANON_WITH_AES_128_CBC_SHA256: return("TLS_DH_ANON_WITH_AES_128_CBC_SHA256");
case TLS_DH_ANON_WITH_AES_256_CBC_SHA256: return("TLS_DH_ANON_WITH_AES_256_CBC_SHA256");
case TLS_DH_ANON_WITH_AES_128_GCM_SHA256: return("TLS_DH_ANON_WITH_AES_128_GCM_SHA256");
case TLS_DH_ANON_WITH_AES_256_GCM_SHA384: return("TLS_DH_ANON_WITH_AES_256_GCM_SHA384");
case TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA: return("TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA");
case TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA: return("TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA");
case TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256: return("TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256");
case TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DH_ANON_WITH_SEED_CBC_SHA: return("TLS_DH_ANON_WITH_SEED_CBC_SHA");
case TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256: return("TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256");
case TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384: return("TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384");
case TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256: return("TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256");
case TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384: return("TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384");
case TLS_ECDH_RSA_WITH_NULL_SHA: return("TLS_ECDH_RSA_WITH_NULL_SHA");
case TLS_ECDH_RSA_WITH_RC4_128_SHA: return("TLS_ECDH_RSA_WITH_RC4_128_SHA");
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: return("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA");
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: return("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA");
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: return("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256");
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: return("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384");
case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: return("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256");
case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: return("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384");
case TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256: return("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256");
case TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384: return("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384");
case TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256: return("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256");
case TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384: return("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384");
case TLS_ECDHE_RSA_WITH_NULL_SHA: return("TLS_ECDHE_RSA_WITH_NULL_SHA");
case TLS_ECDHE_RSA_WITH_RC4_128_SHA: return("TLS_ECDHE_RSA_WITH_RC4_128_SHA");
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: return("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: return("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256");
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: return("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384");
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: return("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: return("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
case TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256: return("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256");
case TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384: return("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384");
case TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256: return("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256");
case TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384: return("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384");
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: return("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256");
case TLS_ECDH_ECDSA_WITH_NULL_SHA: return("TLS_ECDH_ECDSA_WITH_NULL_SHA");
case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: return("TLS_ECDH_ECDSA_WITH_RC4_128_SHA");
case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: return("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA");
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: return("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA");
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: return("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256");
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: return("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384");
case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: return("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256");
case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: return("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384");
case TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256: return("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256");
case TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384: return("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384");
case TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256: return("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256");
case TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384: return("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384");
case TLS_ECDHE_ECDSA_WITH_NULL_SHA: return("TLS_ECDHE_ECDSA_WITH_NULL_SHA");
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: return("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA");
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: return("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA");
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: return("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA");
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: return("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256");
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: return("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384");
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: return("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: return("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: return("TLS_ECDHE_ECDSA_WITH_AES_128_CCM");
case TLS_ECDHE_ECDSA_WITH_AES_256_CCM: return("TLS_ECDHE_ECDSA_WITH_AES_256_CCM");
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: return("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8");
case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: return("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8");
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256: return("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256");
case TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384: return("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384");
case TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256: return("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256");
case TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384: return("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384");
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: return("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256");
case TLS_ECDH_ANON_WITH_NULL_SHA: return("TLS_ECDH_ANON_WITH_NULL_SHA");
case TLS_ECDH_ANON_WITH_RC4_128_SHA: return("TLS_ECDH_ANON_WITH_RC4_128_SHA");
case TLS_ECDH_ANON_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDH_ANON_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDH_ANON_WITH_AES_128_CBC_SHA: return("TLS_ECDH_ANON_WITH_AES_128_CBC_SHA");
case TLS_ECDH_ANON_WITH_AES_256_CBC_SHA: return("TLS_ECDH_ANON_WITH_AES_256_CBC_SHA");
case TLS_PSK_WITH_NULL_SHA: return("TLS_PSK_WITH_NULL_SHA");
case TLS_PSK_WITH_NULL_SHA256: return("TLS_PSK_WITH_NULL_SHA256");
case TLS_PSK_WITH_NULL_SHA384: return("TLS_PSK_WITH_NULL_SHA384");
case TLS_PSK_WITH_RC4_128_SHA: return("TLS_PSK_WITH_RC4_128_SHA");
case TLS_PSK_WITH_3DES_EDE_CBC_SHA: return("TLS_PSK_WITH_3DES_EDE_CBC_SHA");
case TLS_PSK_WITH_AES_128_CBC_SHA: return("TLS_PSK_WITH_AES_128_CBC_SHA");
case TLS_PSK_WITH_AES_256_CBC_SHA: return("TLS_PSK_WITH_AES_256_CBC_SHA");
case TLS_PSK_WITH_AES_128_CBC_SHA256: return("TLS_PSK_WITH_AES_128_CBC_SHA256");
case TLS_PSK_WITH_AES_256_CBC_SHA384: return("TLS_PSK_WITH_AES_256_CBC_SHA384");
case TLS_PSK_WITH_AES_128_GCM_SHA256: return("TLS_PSK_WITH_AES_128_GCM_SHA256");
case TLS_PSK_WITH_AES_256_GCM_SHA384: return("TLS_PSK_WITH_AES_256_GCM_SHA384");
case TLS_PSK_WITH_AES_128_CCM: return("TLS_PSK_WITH_AES_128_CCM");
case TLS_PSK_WITH_AES_256_CCM: return("TLS_PSK_WITH_AES_256_CCM");
case TLS_PSK_WITH_AES_128_CCM_8: return("TLS_PSK_WITH_AES_128_CCM_8");
case TLS_PSK_WITH_AES_256_CCM_8: return("TLS_PSK_WITH_AES_256_CCM_8");
case TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_PSK_WITH_ARIA_128_CBC_SHA256: return("TLS_PSK_WITH_ARIA_128_CBC_SHA256");
case TLS_PSK_WITH_ARIA_256_CBC_SHA384: return("TLS_PSK_WITH_ARIA_256_CBC_SHA384");
case TLS_PSK_WITH_ARIA_128_GCM_SHA256: return("TLS_PSK_WITH_ARIA_128_GCM_SHA256");
case TLS_PSK_WITH_ARIA_256_GCM_SHA384: return("TLS_PSK_WITH_ARIA_256_GCM_SHA384");
case TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: return("TLS_PSK_WITH_CHACHA20_POLY1305_SHA256");
case TLS_RSA_PSK_WITH_NULL_SHA: return("TLS_RSA_PSK_WITH_NULL_SHA");
case TLS_RSA_PSK_WITH_NULL_SHA256: return("TLS_RSA_PSK_WITH_NULL_SHA256");
case TLS_RSA_PSK_WITH_NULL_SHA384: return("TLS_RSA_PSK_WITH_NULL_SHA384");
case TLS_RSA_PSK_WITH_RC4_128_SHA: return("TLS_RSA_PSK_WITH_RC4_128_SHA");
case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: return("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA");
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: return("TLS_RSA_PSK_WITH_AES_128_CBC_SHA");
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: return("TLS_RSA_PSK_WITH_AES_256_CBC_SHA");
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: return("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256");
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: return("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384");
case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: return("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256");
case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: return("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384");
case TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256: return("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256");
case TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384: return("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384");
case TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256: return("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256");
case TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384: return("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384");
case TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: return("TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256");
case TLS_DHE_PSK_WITH_NULL_SHA: return("TLS_DHE_PSK_WITH_NULL_SHA");
case TLS_DHE_PSK_WITH_NULL_SHA256: return("TLS_DHE_PSK_WITH_NULL_SHA256");
case TLS_DHE_PSK_WITH_NULL_SHA384: return("TLS_DHE_PSK_WITH_NULL_SHA384");
case TLS_DHE_PSK_WITH_RC4_128_SHA: return("TLS_DHE_PSK_WITH_RC4_128_SHA");
case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: return("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA");
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: return("TLS_DHE_PSK_WITH_AES_128_CBC_SHA");
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: return("TLS_DHE_PSK_WITH_AES_256_CBC_SHA");
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: return("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256");
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: return("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384");
case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: return("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256");
case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: return("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384");
case TLS_DHE_PSK_WITH_AES_128_CCM: return("TLS_DHE_PSK_WITH_AES_128_CCM");
case TLS_DHE_PSK_WITH_AES_256_CCM: return("TLS_DHE_PSK_WITH_AES_256_CCM");
case TLS_DHE_PSK_WITH_AES_128_CCM_8: return("TLS_DHE_PSK_WITH_AES_128_CCM_8");
case TLS_DHE_PSK_WITH_AES_256_CCM_8: return("TLS_DHE_PSK_WITH_AES_256_CCM_8");
case TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: return("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256");
case TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: return("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384");
case TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256: return("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256");
case TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384: return("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384");
case TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256: return("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256");
case TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384: return("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384");
case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: return("TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256");
case TLS_ECDHE_PSK_WITH_NULL_SHA: return("TLS_ECDHE_PSK_WITH_NULL_SHA");
case TLS_ECDHE_PSK_WITH_NULL_SHA256: return("TLS_ECDHE_PSK_WITH_NULL_SHA256");
case TLS_ECDHE_PSK_WITH_NULL_SHA384: return("TLS_ECDHE_PSK_WITH_NULL_SHA384");
case TLS_ECDHE_PSK_WITH_RC4_128_SHA: return("TLS_ECDHE_PSK_WITH_RC4_128_SHA");
case TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: return("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA");
case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: return("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA");
case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: return("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA");
case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: return("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256");
case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: return("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384");
case TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: return("TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256");
case TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: return("TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384");
case TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: return("TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256");
case TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: return("TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256");
case TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: return("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256");
case TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: return("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384");
case TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256: return("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256");
case TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384: return("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384");
case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: return("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256");
case TLS_KRB5_EXPORT_WITH_RC4_40_MD5: return("TLS_KRB5_EXPORT_WITH_RC4_40_MD5");
case TLS_KRB5_EXPORT_WITH_RC4_40_SHA: return("TLS_KRB5_EXPORT_WITH_RC4_40_SHA");
case TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5: return("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5");
case TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA: return("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA");
case TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5: return("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5");
case TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA: return("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA");
case TLS_KRB5_WITH_RC4_128_MD5: return("TLS_KRB5_WITH_RC4_128_MD5");
case TLS_KRB5_WITH_RC4_128_SHA: return("TLS_KRB5_WITH_RC4_128_SHA");
case TLS_KRB5_WITH_IDEA_CBC_MD5: return("TLS_KRB5_WITH_IDEA_CBC_MD5");
case TLS_KRB5_WITH_IDEA_CBC_SHA: return("TLS_KRB5_WITH_IDEA_CBC_SHA");
case TLS_KRB5_WITH_DES_CBC_MD5: return("TLS_KRB5_WITH_DES_CBC_MD5");
case TLS_KRB5_WITH_DES_CBC_SHA: return("TLS_KRB5_WITH_DES_CBC_SHA");
case TLS_KRB5_WITH_3DES_EDE_CBC_MD5: return("TLS_KRB5_WITH_3DES_EDE_CBC_MD5");
case TLS_KRB5_WITH_3DES_EDE_CBC_SHA: return("TLS_KRB5_WITH_3DES_EDE_CBC_SHA");
case TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: return("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA");
case TLS_SRP_SHA_WITH_AES_128_CBC_SHA: return("TLS_SRP_SHA_WITH_AES_128_CBC_SHA");
case TLS_SRP_SHA_WITH_AES_256_CBC_SHA: return("TLS_SRP_SHA_WITH_AES_256_CBC_SHA");
case TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: return("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA");
case TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: return("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA");
case TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: return("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA");
case TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: return("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
case TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: return("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA");
case TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: return("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");
case TLS_ECCPWD_WITH_AES_128_GCM_SHA256: return("TLS_ECCPWD_WITH_AES_128_GCM_SHA256");
case TLS_ECCPWD_WITH_AES_256_GCM_SHA384: return("TLS_ECCPWD_WITH_AES_256_GCM_SHA384");
case TLS_ECCPWD_WITH_AES_128_CCM_SHA256: return("TLS_ECCPWD_WITH_AES_128_CCM_SHA256");
case TLS_ECCPWD_WITH_AES_256_CCM_SHA384: return("TLS_ECCPWD_WITH_AES_256_CCM_SHA384");
case TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC: return("TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC");
case TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC: return("TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC");
case TLS_GOSTR341112_256_WITH_28147_CNT_IMIT: return("TLS_GOSTR341112_256_WITH_28147_CNT_IMIT");
case TLS_AES_128_GCM_SHA256: return("TLS_AES_128_GCM_SHA256");
case TLS_AES_256_GCM_SHA384: return("TLS_AES_256_GCM_SHA384");
case TLS_AES_128_CCM_SHA256: return("TLS_AES_128_CCM_SHA256");
case TLS_AES_128_CCM_8_SHA256: return("TLS_AES_128_CCM_8_SHA256");
case TLS_CHACHA20_POLY1305_SHA256: return("TLS_CHACHA20_POLY1305_SHA256");
case TLS_SM4_GCM_SM3: return("TLS_SM4_GCM_SM3");
case TLS_SM4_CCM_SM3: return("TLS_SM4_CCM_SM3");
case TLS_SHA256_SHA256: return("TLS_SHA256_SHA256");
case TLS_SHA384_SHA384: return("TLS_SHA384_SHA384");
case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: return("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
case TLS_FALLBACK_SCSV: return("TLS_FALLBACK_SCSV");
case TLS_CIPHER_GREASE_RESERVED_0: return("TLS_CIPHER_GREASE_RESERVED_0");
case TLS_CIPHER_GREASE_RESERVED_1: return("TLS_CIPHER_GREASE_RESERVED_1");
case TLS_CIPHER_GREASE_RESERVED_2: return("TLS_CIPHER_GREASE_RESERVED_2");
case TLS_CIPHER_GREASE_RESERVED_3: return("TLS_CIPHER_GREASE_RESERVED_3");
case TLS_CIPHER_GREASE_RESERVED_4: return("TLS_CIPHER_GREASE_RESERVED_4");
case TLS_CIPHER_GREASE_RESERVED_5: return("TLS_CIPHER_GREASE_RESERVED_5");
case TLS_CIPHER_GREASE_RESERVED_6: return("TLS_CIPHER_GREASE_RESERVED_6");
case TLS_CIPHER_GREASE_RESERVED_7: return("TLS_CIPHER_GREASE_RESERVED_7");
case TLS_CIPHER_GREASE_RESERVED_8: return("TLS_CIPHER_GREASE_RESERVED_8");
case TLS_CIPHER_GREASE_RESERVED_9: return("TLS_CIPHER_GREASE_RESERVED_9");
case TLS_CIPHER_GREASE_RESERVED_A: return("TLS_CIPHER_GREASE_RESERVED_A");
case TLS_CIPHER_GREASE_RESERVED_B: return("TLS_CIPHER_GREASE_RESERVED_B");
case TLS_CIPHER_GREASE_RESERVED_C: return("TLS_CIPHER_GREASE_RESERVED_C");
case TLS_CIPHER_GREASE_RESERVED_D: return("TLS_CIPHER_GREASE_RESERVED_D");
case TLS_CIPHER_GREASE_RESERVED_E: return("TLS_CIPHER_GREASE_RESERVED_E");
case TLS_CIPHER_GREASE_RESERVED_F: return("TLS_CIPHER_GREASE_RESERVED_F");
default:
{
static char buf[8];
snprintf(buf, sizeof(buf), "0X%04X", cipher);
return(buf);
}
}
}
/* ******************************************************************** */
static inline int ndpi_is_other_char(char c) {
return((c == '.')
|| (c == ' ')
|| (c == '@')
|| (c == '/')
);
}
/* ******************************************************************** */
static int _ndpi_is_valid_char(char c) {
if(ispunct(c) && (!ndpi_is_other_char(c)))
return(0);
else
return(isdigit(c)
|| isalpha(c)
|| ndpi_is_other_char(c));
}
static char ndpi_is_valid_char_tbl[256],ndpi_is_valid_char_tbl_init=0;
static void _ndpi_is_valid_char_init(void) {
int c;
for(c=0; c < 256; c++) ndpi_is_valid_char_tbl[c] = _ndpi_is_valid_char(c);
ndpi_is_valid_char_tbl_init = 1;
}
static inline int ndpi_is_valid_char(char c) {
if(!ndpi_is_valid_char_tbl_init)
_ndpi_is_valid_char_init();
return ndpi_is_valid_char_tbl[(unsigned char)c];
}
/* ******************************************************************** */
static int ndpi_find_non_eng_bigrams(struct ndpi_detection_module_struct *ndpi_struct,
char *str) {
char s[3];
if((isdigit(str[0]) && isdigit(str[1]))
|| ndpi_is_other_char(str[0])
|| ndpi_is_other_char(str[1])
)
return(1);
s[0] = tolower(str[0]), s[1] = tolower(str[1]), s[2] = '\0';
return(ndpi_match_bigram(s));
}
/* ******************************************************************** */
/* #define PRINT_STRINGS 1 */
int ndpi_has_human_readeable_string(struct ndpi_detection_module_struct *ndpi_struct,
char *buffer, u_int buffer_size,
u_int8_t min_string_match_len,
char *outbuf, u_int outbuf_len) {
u_int ret = 0, i = 0, do_cr = 0, len = 0, o_idx = 0, being_o_idx = 0;
if(buffer_size <= 0)
return(0);
outbuf_len--;
outbuf[outbuf_len] = '\0';
for(i=0; i> %c%c\n", isprint(buffer[i]) ? buffer[i] : '.', isprint(buffer[i+1]) ? buffer[i+1] : '.');
if(do_cr) {
if(len > min_string_match_len)
ret = 1;
else {
o_idx = being_o_idx;
being_o_idx = o_idx;
outbuf[o_idx] = '\0';
}
#ifdef PRINT_STRINGS
printf(" [len: %u]%s\n", len, ret ? "<-- HIT" : "");
#endif
if(ret)
break;
do_cr = 0, len = 0;
}
}
}
#ifdef PRINT_STRINGS
printf("=======>> Found string: %u\n", ret);
#endif
return(ret);
}
/* ********************************** */
static const char* ndpi_get_flow_info_by_proto_id(struct ndpi_flow_struct const * const flow,
u_int16_t proto_id)
{
switch (proto_id)
{
case NDPI_PROTOCOL_DNS:
case NDPI_PROTOCOL_HTTP:
return (char const *)flow->host_server_name;
case NDPI_PROTOCOL_QUIC:
case NDPI_PROTOCOL_TLS:
if (flow->protos.tls_quic_stun.tls_quic.hello_processed != 0)
{
return flow->protos.tls_quic_stun.tls_quic.client_requested_server_name;
}
break;
}
return NULL;
}
const char* ndpi_get_flow_info(struct ndpi_flow_struct const * const flow,
ndpi_protocol const * const l7_protocol)
{
char const * const app_protocol_info = ndpi_get_flow_info_by_proto_id(flow, l7_protocol->app_protocol);
if (app_protocol_info != NULL)
{
return app_protocol_info;
}
return ndpi_get_flow_info_by_proto_id(flow, l7_protocol->master_protocol);
}
/* ********************************** */
char* ndpi_ssl_version2str(struct ndpi_flow_struct *flow,
u_int16_t version, u_int8_t *unknown_tls_version) {
if(unknown_tls_version)
*unknown_tls_version = 0;
switch(version) {
case 0x0300: return("SSLv3");
case 0x0301: return("TLSv1");
case 0x0302: return("TLSv1.1");
case 0x0303: return("TLSv1.2");
case 0x0304: return("TLSv1.3");
case 0XFB1A: return("TLSv1.3 (Fizz)"); /* https://engineering.fb.com/security/fizz/ */
case 0XFEFF: return("DTLSv1.0");
case 0XFEFD: return("DTLSv1.2");
case 0x0A0A:
case 0x1A1A:
case 0x2A2A:
case 0x3A3A:
case 0x4A4A:
case 0x5A5A:
case 0x6A6A:
case 0x7A7A:
case 0x8A8A:
case 0x9A9A:
case 0xAAAA:
case 0xBABA:
case 0xCACA:
case 0xDADA:
case 0xEAEA:
case 0xFAFA: return("GREASE");
}
if((version >= 0x7f00) && (version <= 0x7fff))
return("TLSv1.3 (draft)");
if(unknown_tls_version)
*unknown_tls_version = 1;
if(flow != NULL) {
snprintf(flow->protos.tls_quic_stun.tls_quic.ssl_version_str,
sizeof(flow->protos.tls_quic_stun.tls_quic.ssl_version_str), "TLS (%04X)", version);
return(flow->protos.tls_quic_stun.tls_quic.ssl_version_str);
} else
return("");
}
/* ***************************************************** */
void ndpi_patchIPv6Address(char *str) {
int i = 0, j = 0;
while(str[i] != '\0') {
if((str[i] == ':')
&& (str[i+1] == '0')
&& (str[i+2] == ':')) {
str[j++] = ':';
str[j++] = ':';
i += 3;
} else
str[j++] = str[i++];
}
if(str[j] != '\0') str[j] = '\0';
}
/* ********************************** */
void ndpi_user_pwd_payload_copy(u_int8_t *dest, u_int dest_len,
u_int offset,
const u_int8_t *src, u_int src_len) {
u_int i, j=0, k = dest_len-1;
for(i=offset; (i> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if(pad) {
if(pad == 1)
pos--;
else if(pad == 2)
pos -= 2;
else {
/* Invalid padding */
ndpi_free(out);
return NULL;
}
break;
}
}
}
*out_len = pos - out;
return out;
}
/* ********************************** */
/* NOTE: caller MUST free returned pointer */
char* ndpi_base64_encode(unsigned char const* bytes_to_encode, size_t in_len) {
size_t len = 0, ret_size;
char *ret;
int j, i = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
ret_size = ((in_len+2)/3)*4;
if((ret = (char*)ndpi_malloc(ret_size+1)) == NULL)
return NULL;
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if(i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; i < 4; i++)
ret[len++] = base64_table[char_array_4[i]];
i = 0;
}
}
if(i) {
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(j = 0; (j < i + 1); j++)
ret[len++] = base64_table[char_array_4[j]];
while((i++ < 3))
ret[len++] = '=';
}
ret[len++] = '\0';
return ret;
}
/* ********************************** */
void ndpi_serialize_risk(ndpi_serializer *serializer,
struct ndpi_flow_struct *flow) {
if(flow->risk != 0) {
u_int32_t i;
ndpi_serialize_start_of_block(serializer, "flow_risk");
for(i = 0; i < NDPI_MAX_RISK; i++) {
ndpi_risk_enum r = (ndpi_risk_enum)i;
if(NDPI_ISSET_BIT(flow->risk, r))
ndpi_serialize_uint32_string(serializer, i, ndpi_risk2str(r));
}
ndpi_serialize_end_of_block(serializer);
}
}
/* ********************************** */
/* ********************************** */
/* NOTE: serializer must have been already initialized */
int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
ndpi_protocol l7_protocol,
ndpi_serializer *serializer) {
char buf[64];
if(flow == NULL) return(-1);
ndpi_serialize_start_of_block(serializer, "ndpi");
ndpi_serialize_risk(serializer, flow);
if (l7_protocol.master_protocol == NDPI_PROTOCOL_IP_ICMP && flow->entropy > 0.0f) {
ndpi_serialize_string_float(serializer, "entropy", flow->entropy, "%.6f");
}
ndpi_serialize_string_string(serializer, "proto", ndpi_protocol2name(ndpi_struct, l7_protocol, buf, sizeof(buf)));
ndpi_protocol_breed_t breed =
ndpi_get_proto_breed(ndpi_struct,
(l7_protocol.app_protocol != NDPI_PROTOCOL_UNKNOWN ? l7_protocol.app_protocol : l7_protocol.master_protocol));
ndpi_serialize_string_string(serializer, "breed", ndpi_get_proto_breed_name(ndpi_struct, breed));
if(l7_protocol.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)
ndpi_serialize_string_string(serializer, "category", ndpi_category_get_name(ndpi_struct, l7_protocol.category));
ndpi_serialize_end_of_block(serializer);
switch(l7_protocol.master_protocol ? l7_protocol.master_protocol : l7_protocol.app_protocol) {
case NDPI_PROTOCOL_DHCP:
ndpi_serialize_start_of_block(serializer, "dhcp");
ndpi_serialize_string_string(serializer, "fingerprint", flow->protos.dhcp.fingerprint);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_BITTORRENT:
{
u_int i, j, n = 0;
char bittorent_hash[sizeof(flow->protos.bittorrent.hash)*2+1];
for(i=0, j = 0; j < sizeof(bittorent_hash)-1; i++) {
sprintf(&bittorent_hash[j], "%02x",
flow->protos.bittorrent.hash[i]);
j += 2, n += flow->protos.bittorrent.hash[i];
}
if(n == 0) bittorent_hash[0] = '\0';
ndpi_serialize_start_of_block(serializer, "bittorrent");
ndpi_serialize_string_string(serializer, "hash", bittorent_hash);
ndpi_serialize_end_of_block(serializer);
}
break;
case NDPI_PROTOCOL_DNS:
ndpi_serialize_start_of_block(serializer, "dns");
if(flow->host_server_name[0] != '\0')
ndpi_serialize_string_string(serializer, "query", (const char*)flow->host_server_name);
ndpi_serialize_string_uint32(serializer, "num_queries", flow->protos.dns.num_queries);
ndpi_serialize_string_uint32(serializer, "num_answers", flow->protos.dns.num_answers);
ndpi_serialize_string_uint32(serializer, "reply_code", flow->protos.dns.reply_code);
ndpi_serialize_string_uint32(serializer, "query_type", flow->protos.dns.query_type);
ndpi_serialize_string_uint32(serializer, "rsp_type", flow->protos.dns.rsp_type);
inet_ntop(AF_INET, &flow->protos.dns.rsp_addr, buf, sizeof(buf));
ndpi_serialize_string_string(serializer, "rsp_addr", buf);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_MDNS:
ndpi_serialize_start_of_block(serializer, "mdns");
ndpi_serialize_string_string(serializer, "answer", (const char*)flow->host_server_name);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_UBNTAC2:
ndpi_serialize_start_of_block(serializer, "ubntac2");
ndpi_serialize_string_string(serializer, "version", flow->protos.ubntac2.version);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_KERBEROS:
ndpi_serialize_start_of_block(serializer, "kerberos");
ndpi_serialize_string_string(serializer, "hostname", flow->protos.kerberos.hostname);
ndpi_serialize_string_string(serializer, "domain", flow->protos.kerberos.domain);
ndpi_serialize_string_string(serializer, "username", flow->protos.kerberos.username);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_TELNET:
ndpi_serialize_start_of_block(serializer, "telnet");
ndpi_serialize_string_string(serializer, "username", flow->protos.telnet.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.telnet.password);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_HTTP:
ndpi_serialize_start_of_block(serializer, "http");
if(flow->host_server_name[0] != '\0')
ndpi_serialize_string_string(serializer, "hostname", (const char*)flow->host_server_name);
if(flow->http.url != NULL){
ndpi_serialize_string_string(serializer, "url", flow->http.url);
ndpi_serialize_string_uint32(serializer, "code", flow->http.response_status_code);
ndpi_serialize_string_string(serializer, "content_type", flow->http.content_type);
ndpi_serialize_string_string(serializer, "user_agent", flow->http.user_agent);
}
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_QUIC:
ndpi_serialize_start_of_block(serializer, "quic");
if(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0')
ndpi_serialize_string_string(serializer, "client_requested_server_name",
flow->protos.tls_quic_stun.tls_quic.client_requested_server_name);
if(flow->http.user_agent)
ndpi_serialize_string_string(serializer, "user_agent", flow->http.user_agent);
if(flow->protos.tls_quic_stun.tls_quic.ssl_version) {
u_int8_t unknown_tls_version;
char *version = ndpi_ssl_version2str(flow, flow->protos.tls_quic_stun.tls_quic.ssl_version, &unknown_tls_version);
if(!unknown_tls_version)
ndpi_serialize_string_string(serializer, "version", version);
if(flow->protos.tls_quic_stun.tls_quic.alpn)
ndpi_serialize_string_string(serializer, "alpn", flow->protos.tls_quic_stun.tls_quic.alpn);
ndpi_serialize_string_string(serializer, "ja3", flow->protos.tls_quic_stun.tls_quic.ja3_client);
if(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions)
ndpi_serialize_string_string(serializer, "tls_supported_versions", flow->protos.tls_quic_stun.tls_quic.tls_supported_versions);
}
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_MAIL_IMAP:
ndpi_serialize_start_of_block(serializer, "imap");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_MAIL_POP:
ndpi_serialize_start_of_block(serializer, "pop");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_MAIL_SMTP:
ndpi_serialize_start_of_block(serializer, "smtp");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_FTP_CONTROL:
ndpi_serialize_start_of_block(serializer, "ftp");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_string_uint32(serializer, "auth_failed", flow->protos.ftp_imap_pop_smtp.auth_failed);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_SSH:
ndpi_serialize_start_of_block(serializer, "ssh");
ndpi_serialize_string_string(serializer, "client_signature", flow->protos.ssh.client_signature);
ndpi_serialize_string_string(serializer, "server_signature", flow->protos.ssh.server_signature);
ndpi_serialize_string_string(serializer, "hassh_client", flow->protos.ssh.hassh_client);
ndpi_serialize_string_string(serializer, "hassh_server", flow->protos.ssh.hassh_server);
ndpi_serialize_end_of_block(serializer);
break;
case NDPI_PROTOCOL_TLS:
case NDPI_PROTOCOL_DTLS:
if(flow->protos.tls_quic_stun.tls_quic.ssl_version) {
char notBefore[32], notAfter[32];
struct tm a, b, *before = NULL, *after = NULL;
u_int i, off;
u_int8_t unknown_tls_version;
char *version = ndpi_ssl_version2str(flow, flow->protos.tls_quic_stun.tls_quic.ssl_version, &unknown_tls_version);
if(flow->protos.tls_quic_stun.tls_quic.notBefore)
before = gmtime_r((const time_t *)&flow->protos.tls_quic_stun.tls_quic.notBefore, &a);
if(flow->protos.tls_quic_stun.tls_quic.notAfter)
after = gmtime_r((const time_t *)&flow->protos.tls_quic_stun.tls_quic.notAfter, &b);
if(!unknown_tls_version) {
ndpi_serialize_start_of_block(serializer, "tls");
ndpi_serialize_string_string(serializer, "version", version);
ndpi_serialize_string_string(serializer, "client_requested_server_name",
flow->protos.tls_quic_stun.tls_quic.client_requested_server_name);
if(flow->protos.tls_quic_stun.tls_quic.server_names)
ndpi_serialize_string_string(serializer, "server_names", flow->protos.tls_quic_stun.tls_quic.server_names);
if(before) {
strftime(notBefore, sizeof(notBefore), "%Y-%m-%d %H:%M:%S", before);
ndpi_serialize_string_string(serializer, "notbefore", notBefore);
}
if(after) {
strftime(notAfter, sizeof(notAfter), "%Y-%m-%d %H:%M:%S", after);
ndpi_serialize_string_string(serializer, "notafter", notAfter);
}
ndpi_serialize_string_string(serializer, "ja3", flow->protos.tls_quic_stun.tls_quic.ja3_client);
ndpi_serialize_string_string(serializer, "ja3s", flow->protos.tls_quic_stun.tls_quic.ja3_server);
ndpi_serialize_string_uint32(serializer, "unsafe_cipher", flow->protos.tls_quic_stun.tls_quic.server_unsafe_cipher);
ndpi_serialize_string_string(serializer, "cipher", ndpi_cipher2str(flow->protos.tls_quic_stun.tls_quic.server_cipher));
if(flow->protos.tls_quic_stun.tls_quic.issuerDN)
ndpi_serialize_string_string(serializer, "issuerDN", flow->protos.tls_quic_stun.tls_quic.issuerDN);
if(flow->protos.tls_quic_stun.tls_quic.subjectDN)
ndpi_serialize_string_string(serializer, "issuerDN", flow->protos.tls_quic_stun.tls_quic.subjectDN);
if(flow->protos.tls_quic_stun.tls_quic.alpn)
ndpi_serialize_string_string(serializer, "alpn", flow->protos.tls_quic_stun.tls_quic.alpn);
if(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions)
ndpi_serialize_string_string(serializer, "tls_supported_versions", flow->protos.tls_quic_stun.tls_quic.tls_supported_versions);
if(flow->protos.tls_quic_stun.tls_quic.sha1_certificate_fingerprint[0] != '\0') {
for(i=0, off=0; i<20; i++) {
int rc = snprintf(&buf[off], sizeof(buf)-off,"%s%02X", (i > 0) ? ":" : "",
flow->protos.tls_quic_stun.tls_quic.sha1_certificate_fingerprint[i] & 0xFF);
if(rc <= 0) break; else off += rc;
}
ndpi_serialize_string_string(serializer, "fingerprint", buf);
}
ndpi_serialize_end_of_block(serializer);
}
}
break;
} /* switch */
return(0);
}
/* ********************************** */
/* NOTE: serializer is initialized by the function */
int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
u_int8_t ip_version,
u_int8_t l4_protocol, u_int16_t vlan_id,
u_int32_t src_v4, u_int32_t dst_v4,
struct ndpi_in6_addr *src_v6, struct ndpi_in6_addr *dst_v6,
u_int16_t src_port, u_int16_t dst_port,
ndpi_protocol l7_protocol,
ndpi_serializer *serializer) {
char src_name[32], dst_name[32];
if(ndpi_init_serializer(serializer, ndpi_serialization_format_json) == -1)
return(-1);
if(ip_version == 4) {
inet_ntop(AF_INET, &src_v4, src_name, sizeof(src_name));
inet_ntop(AF_INET, &dst_v4, dst_name, sizeof(dst_name));
} else {
inet_ntop(AF_INET6, src_v6, src_name, sizeof(src_name));
inet_ntop(AF_INET6, dst_v6, dst_name, sizeof(dst_name));
/* For consistency across platforms replace :0: with :: */
ndpi_patchIPv6Address(src_name), ndpi_patchIPv6Address(dst_name);
}
ndpi_serialize_string_string(serializer, "src_ip", src_name);
ndpi_serialize_string_string(serializer, "dest_ip", dst_name);
if(src_port) ndpi_serialize_string_uint32(serializer, "src_port", src_port);
if(dst_port) ndpi_serialize_string_uint32(serializer, "dst_port", dst_port);
switch(l4_protocol) {
case IPPROTO_TCP:
ndpi_serialize_string_string(serializer, "proto", "TCP");
break;
case IPPROTO_UDP:
ndpi_serialize_string_string(serializer, "proto", "UDP");
break;
case IPPROTO_ICMP:
ndpi_serialize_string_string(serializer, "proto", "ICMP");
break;
default:
ndpi_serialize_string_uint32(serializer, "proto", l4_protocol);
break;
}
return(ndpi_dpi2json(ndpi_struct, flow, l7_protocol, serializer));
}
/* ********************************** */
const char* ndpi_tunnel2str(ndpi_packet_tunnel tt) {
switch(tt) {
case ndpi_no_tunnel:
return("No-Tunnel");
break;
case ndpi_gtp_tunnel:
return("GTP");
break;
case ndpi_capwap_tunnel:
return("CAPWAP");
break;
case ndpi_tzsp_tunnel:
return("TZSP");
break;
case ndpi_l2tp_tunnel:
return("L2TP");
break;
case ndpi_vxlan_tunnel:
return("VXLAN");
break;
}
return("");
}
/* ********************************** */
/*
/dv/vulnerabilities/xss_r/?name=%3Cscript%3Econsole.log%28%27JUL2D3WXHEGWRAFJE2PI7OS71Z4Z8RFUHXGNFLUFYVP6M3OL55%27%29%3Bconsole.log%28document.cookie%29%3B%3C%2Fscript%3E
/dv/vulnerabilities/sqli/?id=1%27+and+1%3D1+union+select+null%2C+table_name+from+information_schema.tables%23&Submit=Submit
*/
/* https://www.rosettacode.org/wiki/URL_decoding#C */
static int ishex(int x) {
return(x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F');
}
/* ********************************** */
static int ndpi_url_decode(const char *s, char *out) {
char *o;
const char *end = s + strlen(s);
int c;
for(o = out; s <= end; o++) {
c = *s++;
if(c == '+') c = ' ';
else if(c == '%' && (!ishex(*s++)||
!ishex(*s++)||
!sscanf(s - 2, "%2x", (unsigned int*)&c)))
return(-1);
if(out) *o = c;
}
return(o - out);
}
/* ********************************** */
static int ndpi_is_sql_injection(char* query) {
struct libinjection_sqli_state state;
size_t qlen = strlen(query);
libinjection_sqli_init(&state, query, qlen, FLAG_NONE);
return libinjection_is_sqli(&state);
}
/* ********************************** */
static int ndpi_is_xss_injection(char* query) {
size_t qlen = strlen(query);
return libinjection_xss(query, qlen);
}
/* ********************************** */
#ifdef HAVE_PCRE
static void ndpi_compile_rce_regex() {
const char *pcreErrorStr;
int pcreErrorOffset;
for(int i = 0; i < N_RCE_REGEX; i++) {
comp_rx[i] = (struct pcre_struct*)ndpi_malloc(sizeof(struct pcre_struct));
comp_rx[i]->compiled = pcre_compile(rce_regex[i], 0, &pcreErrorStr,
&pcreErrorOffset, NULL);
if(comp_rx[i]->compiled == NULL) {
#ifdef DEBUG
NDPI_LOG_ERR(ndpi_str, "ERROR: Could not compile '%s': %s\n", rce_regex[i],
pcreErrorStr);
#endif
continue;
}
comp_rx[i]->optimized = pcre_study(comp_rx[i]->compiled, 0, &pcreErrorStr);
#ifdef DEBUG
if(pcreErrorStr != NULL) {
NDPI_LOG_ERR(ndpi_str, "ERROR: Could not study '%s': %s\n", rce_regex[i],
pcreErrorStr);
}
#endif
}
free((void *)pcreErrorStr);
}
static int ndpi_is_rce_injection(char* query) {
if(!initialized_comp_rx) {
ndpi_compile_rce_regex();
initialized_comp_rx = 1;
}
int pcreExecRet;
int subStrVec[30];
for(int i = 0; i < N_RCE_REGEX; i++) {
unsigned int length = strlen(query);
pcreExecRet = pcre_exec(comp_rx[i]->compiled,
comp_rx[i]->optimized,
query, length, 0, 0, subStrVec, 30);
if(pcreExecRet >= 0) {
return 1;
}
#ifdef DEBUG
else {
switch(pcreExecRet) {
case PCRE_ERROR_NOMATCH:
NDPI_LOG_ERR(ndpi_str, "ERROR: String did not match the pattern\n");
break;
case PCRE_ERROR_NULL:
NDPI_LOG_ERR(ndpi_str, "ERROR: Something was null\n");
break;
case PCRE_ERROR_BADOPTION:
NDPI_LOG_ERR(ndpi_str, "ERROR: A bad option was passed\n");
break;
case PCRE_ERROR_BADMAGIC:
NDPI_LOG_ERR(ndpi_str, "ERROR: Magic number bad (compiled re corrupt?)\n");
break;
case PCRE_ERROR_UNKNOWN_NODE:
NDPI_LOG_ERR(ndpi_str, "ERROR: Something kooky in the compiled re\n");
break;
case PCRE_ERROR_NOMEMORY:
NDPI_LOG_ERR(ndpi_str, "ERROR: Ran out of memory\n");
break;
default:
NDPI_LOG_ERR(ndpi_str, "ERROR: Unknown error\n");
break;
}
}
#endif
}
size_t ushlen = sizeof(ush_commands) / sizeof(ush_commands[0]);
for(int i = 0; i < ushlen; i++) {
if(strstr(query, ush_commands[i]) != NULL) {
return 1;
}
}
size_t pwshlen = sizeof(pwsh_commands) / sizeof(pwsh_commands[0]);
for(int i = 0; i < pwshlen; i++) {
if(strstr(query, pwsh_commands[i]) != NULL) {
return 1;
}
}
return 0;
}
#endif
/* ********************************** */
ndpi_risk_enum ndpi_validate_url(char *url) {
char *orig_str = NULL, *str = NULL, *question_mark = strchr(url, '?');
ndpi_risk_enum rc = NDPI_NO_RISK;
if(question_mark) {
char *tmp;
orig_str = str = ndpi_strdup(&question_mark[1]); /* Skip ? */
if(!str) goto validate_rc;
str = strtok_r(str, "&", &tmp);
while(str != NULL) {
char *value = strchr(str, '=');
char *decoded;
if(!value)
break;
else
value = &value[1];
if(value[0] != '\0') {
if(!(decoded = (char*)ndpi_malloc(strlen(value)+1)))
break;
if(ndpi_url_decode(value, decoded) < 0) {
/* Invalid string */
} else if(decoded[0] != '\0') {
/* Valid string */
if(ndpi_is_xss_injection(decoded))
rc = NDPI_URL_POSSIBLE_XSS;
else if(ndpi_is_sql_injection(decoded))
rc = NDPI_URL_POSSIBLE_SQL_INJECTION;
#ifdef HAVE_PCRE
else if(ndpi_is_rce_injection(decoded))
rc = NDPI_URL_POSSIBLE_RCE_INJECTION;
#endif
#ifdef URL_CHECK_DEBUG
printf("=>> [rc: %u] %s\n", rc, decoded);
#endif
}
ndpi_free(decoded);
if(rc != NDPI_NO_RISK)
break;
}
str = strtok_r(NULL, "&", &tmp);
}
}
validate_rc:
if(orig_str) ndpi_free(orig_str);
if(rc == NDPI_NO_RISK) {
/* Let's do an extra check */
if(strstr(url, "..")) {
/* 127.0.0.1/msadc/..%255c../..%255c../..%255c../winnt/system32/cmd.exe */
rc = NDPI_HTTP_SUSPICIOUS_URL;
}
}
return(rc);
}
/* ******************************************************************** */
u_int8_t ndpi_is_protocol_detected(struct ndpi_detection_module_struct *ndpi_str,
ndpi_protocol proto) {
if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN)
|| (proto.app_protocol != NDPI_PROTOCOL_UNKNOWN)
|| (proto.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED))
return(1);
else
return(0);
}
/* ******************************************************************** */
const char* ndpi_risk2str(ndpi_risk_enum risk) {
static char buf[16];
switch(risk) {
case NDPI_URL_POSSIBLE_XSS:
return("XSS attack");
case NDPI_URL_POSSIBLE_SQL_INJECTION:
return("SQL injection");
case NDPI_URL_POSSIBLE_RCE_INJECTION:
return("RCE injection");
case NDPI_BINARY_APPLICATION_TRANSFER:
return("Binary application transfer");
case NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT:
return("Known protocol on non standard port");
case NDPI_TLS_SELFSIGNED_CERTIFICATE:
return("Self-signed Certificate");
case NDPI_TLS_OBSOLETE_VERSION:
return("Obsolete TLS version (< 1.1)");
case NDPI_TLS_WEAK_CIPHER:
return("Weak TLS cipher");
case NDPI_TLS_CERTIFICATE_EXPIRED:
return("TLS Expired Certificate");
case NDPI_TLS_CERTIFICATE_MISMATCH:
return("TLS Certificate Mismatch");
case NDPI_HTTP_SUSPICIOUS_USER_AGENT:
return("HTTP Suspicious User-Agent");
case NDPI_HTTP_NUMERIC_IP_HOST:
return("HTTP Numeric IP Address");
case NDPI_HTTP_SUSPICIOUS_URL:
return("HTTP Suspicious URL");
case NDPI_HTTP_SUSPICIOUS_HEADER:
return("HTTP Suspicious Header");
case NDPI_TLS_NOT_CARRYING_HTTPS:
return("TLS (probably) not carrying HTTPS");
case NDPI_SUSPICIOUS_DGA_DOMAIN:
return("Suspicious DGA domain name");
case NDPI_MALFORMED_PACKET:
return("Malformed packet");
case NDPI_SSH_OBSOLETE_CLIENT_VERSION_OR_CIPHER:
return("SSH Obsolete Client Version/Cipher");
case NDPI_SSH_OBSOLETE_SERVER_VERSION_OR_CIPHER:
return("SSH Obsolete Server Version/Cipher");
case NDPI_SMB_INSECURE_VERSION:
return("SMB Insecure Version");
case NDPI_TLS_SUSPICIOUS_ESNI_USAGE:
return("TLS Suspicious ESNI Usage");
case NDPI_UNSAFE_PROTOCOL:
return("Unsafe Protocol");
case NDPI_DNS_SUSPICIOUS_TRAFFIC:
return("Suspicious DNS traffic"); /* Exfiltration ? */
case NDPI_TLS_MISSING_SNI:
return("SNI TLS extension was missing");
case NDPI_HTTP_SUSPICIOUS_CONTENT:
return("HTTP suspicious content");
case NDPI_RISKY_ASN:
return("Risky ASN");
case NDPI_RISKY_DOMAIN:
return("Risky domain name");
case NDPI_MALICIOUS_JA3:
return("Possibly Malicious JA3 Fingerprint");
case NDPI_MALICIOUS_SHA1_CERTIFICATE:
return("Possibly Malicious SSL Cert. SHA1 Fingerprint");
case NDPI_DESKTOP_OR_FILE_SHARING_SESSION:
return("Desktop/File Sharing Session");
case NDPI_TLS_UNCOMMON_ALPN:
return("Uncommon TLS ALPN");
case NDPI_TLS_CERT_VALIDITY_TOO_LONG:
return("TLS certificate validity longer than 13 months");
case NDPI_TLS_SUSPICIOUS_EXTENSION:
return("TLS suspicious extension");
case NDPI_TLS_FATAL_ALERT:
return("TLS fatal alert");
case NDPI_SUSPICIOUS_ENTROPY:
return("Suspicious entropy");
case NDPI_CLEAR_TEXT_CREDENTIALS:
return("Clear-text credentials");
default:
snprintf(buf, sizeof(buf), "%d", (int)risk);
return(buf);
}
}
/* ******************************************************************** */
const char* ndpi_severity2str(ndpi_risk_severity s) {
switch(s) {
case NDPI_RISK_LOW:
return("Low");
break;
case NDPI_RISK_MEDIUM:
return("Medium");
break;
case NDPI_RISK_HIGH:
return("High");
break;
case NDPI_RISK_SEVERE:
return("Severe");
break;
}
return("");
}
/* ******************************************************************** */
u_int16_t ndpi_risk2score(ndpi_risk risk,
u_int16_t *client_score,
u_int16_t *server_score) {
u_int16_t score = 0;
u_int32_t i;
*client_score = *server_score = 0; /* Reset values */
if(risk == 0) return(0);
for(i = 0; i < NDPI_MAX_RISK; i++) {
ndpi_risk_enum r = (ndpi_risk_enum)i;
if(NDPI_ISSET_BIT(risk, r)) {
ndpi_risk_info *info = ndpi_risk2severity(r);
u_int16_t val = 0, client_score_val;
switch(info->severity) {
case NDPI_RISK_LOW:
val = NDPI_SCORE_RISK_LOW;
break;
case NDPI_RISK_MEDIUM:
val = NDPI_SCORE_RISK_MEDIUM;
break;
case NDPI_RISK_HIGH:
val = NDPI_SCORE_RISK_HIGH;
break;
case NDPI_RISK_SEVERE:
val = NDPI_SCORE_RISK_SEVERE;
break;
}
score += val;
client_score_val = (val * info->default_client_risk_pctg) / 100;
*client_score += client_score_val, *server_score += (val - client_score_val);
}
}
return(score);
}
/* ******************************************************************** */
const char* ndpi_http_method2str(ndpi_http_method m) {
switch(m) {
case NDPI_HTTP_METHOD_UNKNOWN: break;
case NDPI_HTTP_METHOD_OPTIONS: return("OPTIONS");
case NDPI_HTTP_METHOD_GET: return("GET");
case NDPI_HTTP_METHOD_HEAD: return("HEAD");
case NDPI_HTTP_METHOD_PATCH: return("PATCH");
case NDPI_HTTP_METHOD_POST: return("POST");
case NDPI_HTTP_METHOD_PUT: return("PUT");
case NDPI_HTTP_METHOD_DELETE: return("DELETE");
case NDPI_HTTP_METHOD_TRACE: return("TRACE");
case NDPI_HTTP_METHOD_CONNECT: return("CONNECT");
}
return("Unknown HTTP method");
}
/* ******************************************************************** */
ndpi_http_method ndpi_http_str2method(const char* method, u_int16_t method_len) {
if(!method || method_len < 3)
return(NDPI_HTTP_METHOD_UNKNOWN);
switch(method[0]) {
case 'O': return(NDPI_HTTP_METHOD_OPTIONS);
case 'G': return(NDPI_HTTP_METHOD_GET);
case 'H': return(NDPI_HTTP_METHOD_HEAD);
case 'P':
switch(method[1]) {
case 'A':return(NDPI_HTTP_METHOD_PATCH);
case 'O':return(NDPI_HTTP_METHOD_POST);
case 'U':return(NDPI_HTTP_METHOD_PUT);
}
break;
case 'D': return(NDPI_HTTP_METHOD_DELETE);
case 'T': return(NDPI_HTTP_METHOD_TRACE);
case 'C': return(NDPI_HTTP_METHOD_CONNECT);
}
return(NDPI_HTTP_METHOD_UNKNOWN);
}
/* ******************************************************************** */
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
/*
'in_16_bytes_long` points to some 16 byte memory data to be hashed;
two independent 64-bit linear congruential generators are applied
results are mixed, scrambled and cast to 32-bit
*/
u_int32_t ndpi_quick_16_byte_hash(u_int8_t *in_16_bytes_long) {
u_int64_t a = *(u_int64_t*)(in_16_bytes_long + 0);
u_int64_t c = *(u_int64_t*)(in_16_bytes_long + 8);
// multipliers are taken from sprng.org, addends are prime
a = a * 0x2c6fe96ee78b6955 + 0x9af64480a3486659;
c = c * 0x369dea0f31a53f85 + 0xd0c6225445b76b5b;
// mix results
a += c;
// final scramble
a ^= ROR64(a, 13) ^ ROR64(a, 7);
// down-casting, also taking advantage of upper half
a ^= a >> 32;
return((u_int32_t)a);
}
/* ******************************************************************** */
ndpi_str_hash* ndpi_hash_alloc(u_int32_t max_num_entries) {
ndpi_str_hash *h = (ndpi_str_hash*)ndpi_malloc(sizeof(ndpi_str_hash));
if(!h) return(NULL);
if(max_num_entries < 1024) max_num_entries = 1024;
if(max_num_entries > 10000000) max_num_entries = 10000000;
h->max_num_entries = max_num_entries, h->num_buckets = max_num_entries/2;
h->buckets = (struct ndpi_str_hash_info**)ndpi_calloc(sizeof(struct ndpi_str_hash_info*), h->num_buckets);
if(h->buckets == NULL) {
ndpi_free(h);
return(NULL);
} else
return(h);
}
/* ******************************************************************** */
void ndpi_hash_free(ndpi_str_hash *h) {
u_int32_t i;
for(i=0; inum_buckets; i++) {
struct ndpi_str_hash_info *head = h->buckets[i];
while(head != NULL) {
struct ndpi_str_hash_info *next = head->next;
ndpi_free(head->key);
ndpi_free(head);
head = next;
}
}
ndpi_free(h->buckets);
ndpi_free(h);
}
/* ******************************************************************** */
static u_int32_t _ndpi_hash_function(ndpi_str_hash *h, char *key, u_int8_t key_len) {
u_int32_t hv = 0;
u_int8_t i;
for(i=0; inum_buckets);
}
/* ******************************************************************** */
static int _ndpi_hash_find_entry(ndpi_str_hash *h, u_int32_t hashval, char *key, u_int key_len, u_int8_t *value) {
struct ndpi_str_hash_info *head = h->buckets[hashval];
while(head != NULL) {
if((head->key_len == key_len) && (memcmp(head->key, key, key_len) == 0)) {
*value = head->value;
return(0); /* Found */
}
head = head-> next;
}
return(-1); /* Not found */
}
/* ******************************************************************** */
int ndpi_hash_find_entry(ndpi_str_hash *h, char *key, u_int key_len, u_int8_t *value) {
u_int32_t hv = _ndpi_hash_function(h, key, key_len);
return(_ndpi_hash_find_entry(h, hv, key, key_len, value));
}
/* ******************************************************************** */
int ndpi_hash_add_entry(ndpi_str_hash *h, char *key, u_int8_t key_len, u_int8_t value) {
u_int32_t hv = _ndpi_hash_function(h, key, key_len);
u_int8_t ret_value;
int rc = _ndpi_hash_find_entry(h, hv, key, key_len, &ret_value);
if(rc == -1) {
/* Not found */
struct ndpi_str_hash_info *e = (struct ndpi_str_hash_info*)ndpi_malloc(sizeof(struct ndpi_str_hash_info));
if(e == NULL)
return(-2);
if((e->key = (char*)ndpi_malloc(key_len)) == NULL)
return(-3);
memcpy(e->key, key, key_len);
e->key_len = key_len, e->value = value;
e->next = h->buckets[hv];
h->buckets[hv] = e;
return(0);
} else
return(0);
}
/* ********************************************************************************* */
static u_int64_t ndpi_host_ip_risk_ptree_match(struct ndpi_detection_module_struct *ndpi_str,
struct in_addr *pin /* network byte order */) {
ndpi_prefix_t prefix;
ndpi_patricia_node_t *node;
/* Make sure all in network byte order otherwise compares wont work */
ndpi_fill_prefix_v4(&prefix, pin, 32, ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits);
node = ndpi_patricia_search_best(ndpi_str->ip_risk_mask_ptree, &prefix);
if(node)
return(node->value.u.uv64);
else
return((u_int64_t)-1);
}
/* ********************************************************************************* */
static void ndpi_handle_risk_exceptions(struct ndpi_detection_module_struct *ndpi_str,
struct ndpi_flow_struct *flow) {
char *host;
if(flow->risk == 0) return; /* Nothing to do */
host = ndpi_get_flow_name(flow);
if((!flow->host_risk_mask_evaluated) && (!flow->ip_risk_mask_evaluated)) {
flow->risk_mask = (u_int64_t)-1; /* No mask */
}
if(!flow->host_risk_mask_evaluated) {
if(host && (host[0] != '\0')) {
/* Check host exception */
ndpi_automa *automa = &ndpi_str->host_risk_mask_automa;
if(automa->ac_automa) {
AC_TEXT_t ac_input_text;
AC_REP_t match;
ac_input_text.astring = host, ac_input_text.length = strlen(host);
ac_input_text.option = 0;
if(ac_automata_search(automa->ac_automa, &ac_input_text, &match) > 0)
flow->risk_mask &= match.number64;
}
/* Used to avoid double checks (e.g. in DNS req/rsp) */
flow->host_risk_mask_evaluated = 1;
}
}
/* TODO: add IPv6 support */
if(!flow->ip_risk_mask_evaluated) {
if(flow->packet.iph) {
struct ndpi_packet_struct *packet = &flow->packet;
struct in_addr pin;
pin.s_addr = packet->iph->saddr;
flow->risk_mask &= ndpi_host_ip_risk_ptree_match(ndpi_str, &pin);
pin.s_addr = packet->iph->daddr;
flow->risk_mask &= ndpi_host_ip_risk_ptree_match(ndpi_str, &pin);
}
flow->ip_risk_mask_evaluated = 1;
}
flow->risk &= flow->risk_mask;
}
/* ******************************************************************** */
void ndpi_set_risk(struct ndpi_detection_module_struct *ndpi_str,
struct ndpi_flow_struct *flow, ndpi_risk_enum r) {
ndpi_risk v = 1ull << r;
// NDPI_SET_BIT(flow->risk, (u_int32_t)r);
flow->risk |= v;
ndpi_handle_risk_exceptions(ndpi_str, flow);
}
/* ******************************************************************** */
int ndpi_is_printable_string(char const * const str, size_t len) {
for (size_t i = 0; i < len; ++i) {
if (ndpi_isprint(str[i]) == 0) {
return 0;
}
}
return 1;
}
/* ******************************************************************** */
float ndpi_entropy(u_int8_t const * const buf, size_t len) {
float entropy = 0.0f;
u_int32_t byte_counters[256];
memset(byte_counters, 0, sizeof(byte_counters));
for (size_t i = 0; i < len; ++i) {
byte_counters[buf[i]]++;
}
for (size_t i = 0; i < sizeof(byte_counters) / sizeof(byte_counters[0]); ++i) {
if (byte_counters[i] == 0) {
continue;
}
float const p = (float)byte_counters[i] / len;
entropy += p * log2f(1 / p);
}
return entropy;
}
/* ******************************************* */
char* ndpi_get_flow_name(struct ndpi_flow_struct *flow) {
if(!flow) goto no_flow_info;
if(flow->host_server_name[0] != '\0')
return((char*)flow->host_server_name);
if(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0')
return(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name);
no_flow_info:
return((char*)"");
}
/* ******************************************* */
void load_common_alpns(struct ndpi_detection_module_struct *ndpi_str) {
/* see: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */
const char* const common_alpns[] = {
"http/0.9", "http/1.0", "http/1.1",
"spdy/1", "spdy/2", "spdy/3", "spdy/3.1",
"stun.turn", "stun.nat-discovery",
"h2", "h2c", "h2-16", "h2-15", "h2-14", "h2-fb",
"webrtc", "c-webrtc",
"ftp", "imap", "pop3", "managesieve", "coap",
"xmpp-client", "xmpp-server",
"acme-tls/1",
"mqtt", "dot", "ntske/1", "sunrpc",
"h3",
"smb",
"irc",
/* QUIC ALPNs */
"h3-T051", "h3-T050",
"h3-32", "h3-30", "h3-29", "h3-28", "h3-27", "h3-24", "h3-22",
"hq-30", "hq-29", "hq-28", "hq-27",
"h3-fb-05", "h1q-fb",
"doq-i00",
NULL /* end */
};
u_int i;
for(i=0; common_alpns[i] != NULL; i++) {
AC_PATTERN_t ac_pattern;
memset(&ac_pattern, 0, sizeof(ac_pattern));
ac_pattern.astring = ndpi_strdup((char*)common_alpns[i]);
ac_pattern.length = strlen(common_alpns[i]);
if(ac_automata_add(ndpi_str->common_alpns_automa.ac_automa, &ac_pattern) != ACERR_SUCCESS)
printf("%s(): unable to add %s\n", __FUNCTION__, common_alpns[i]);
}
}
/* ******************************************* */
u_int8_t is_a_common_alpn(struct ndpi_detection_module_struct *ndpi_str,
const char *alpn_to_check, u_int alpn_to_check_len) {
ndpi_automa *automa = &ndpi_str->common_alpns_automa;
if(automa->ac_automa) {
AC_TEXT_t ac_input_text;
AC_REP_t match;
ac_input_text.astring = (char*)alpn_to_check, ac_input_text.length = alpn_to_check_len;
ac_input_text.option = 0;
if(ac_automata_search(automa->ac_automa, &ac_input_text, &match) > 0)
return(1);
}
return(0);
}
/* ******************************************* */
u_int8_t ndpi_is_valid_protoId(u_int16_t protoId) {
return((protoId >= NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS) ? 0 : 1);
}
/* ******************************************* */
u_int8_t ndpi_is_encrypted_proto(struct ndpi_detection_module_struct *ndpi_str,
ndpi_protocol proto) {
if(ndpi_is_valid_protoId(proto.master_protocol) && ndpi_is_valid_protoId(proto.app_protocol)) {
return((ndpi_str->proto_defaults[proto.master_protocol].isClearTextProto
&& ndpi_str->proto_defaults[proto.app_protocol].isClearTextProto) ? 0 : 1);
} else
return(0);
}