"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/file-process/file_resume_block.c" (16 Oct 2020, 17694 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "file_resume_block.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /*
    2  ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    3  ** Copyright (C) 2012-2013 Sourcefire, Inc.
    4  **
    5  ** This program is free software; you can redistribute it and/or modify
    6  ** it under the terms of the GNU General Public License Version 2 as
    7  ** published by the Free Software Foundation.  You may not use, modify or
    8  ** distribute this program under any other version of the GNU General
    9  ** Public License.
   10  **
   11  ** This program is distributed in the hope that it will be useful,
   12  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  ** GNU General Public License for more details.
   15  **
   16  ** You should have received a copy of the GNU General Public License
   17  ** along with this program; if not, write to the Free Software
   18  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19  **
   20  **  Author(s):  Hui Cao <hcao@sourcefire.com>
   21  **
   22  **  NOTES
   23  **  9.25.2012 - Initial Source Code. Hcao
   24  */
   25 
   26 #ifdef HAVE_CONFIG_H
   27 #include "config.h"
   28 #endif
   29 
   30 #include <pthread.h>
   31 #include "file_resume_block.h"
   32 #include "sf_types.h"
   33 #include "file_api.h"
   34 #include "snort_bounds.h"
   35 #include "ipv6_port.h"
   36 #include "sfxhash.h"
   37 #include "util.h"
   38 #include "decode.h"
   39 #include "active.h"
   40 #include "sf_sechash.h"
   41 #include "file_config.h"
   42 #include "file_service.h"
   43 #include "file_ss.h"
   44 #include "sidechannel.h"
   45 #include "file_lib.h"
   46 
   47 
   48 /* The hash table of expected files */
   49 static SFXHASH *fileHash = NULL;
   50 extern FileServiceConfig cur_config;
   51 extern FileContext* get_main_file_context(void *ssnptr);
   52 
   53 static FileState sig_file_state = { FILE_CAPTURE_SUCCESS, FILE_SIG_DONE };
   54 /* this file_cache_mutex is used to synchronize multiple add's to SFXHASH */
   55 static pthread_mutex_t file_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
   56 
   57 typedef struct _FileHashKey
   58 {
   59     struct in6_addr sip;
   60     struct in6_addr dip;
   61     uint32_t file_sig;
   62 } FileHashKey;
   63 
   64 typedef struct _FileNode
   65 {
   66     time_t expires;
   67     File_Verdict verdict;
   68     uint32_t   file_type_id;
   69     uint8_t sha256[SHA256_HASH_SIZE];
   70 } FileNode;
   71 
   72 #define MAX_FILES_TRACKED 16384
   73 
   74 void file_resume_block_init(void)
   75 {
   76     /* number of entries * overhead per entry */
   77     unsigned long maxmem = sfxhash_calc_maxmem(MAX_FILES_TRACKED,
   78             sizeof(FileHashKey) + sizeof(FileNode));
   79 
   80     fileHash = sfxhash_new(MAX_FILES_TRACKED, sizeof(FileHashKey), sizeof(FileNode),
   81             maxmem, 1, NULL, NULL, 1);
   82 
   83     if (!fileHash)
   84         FatalError("Failed to create the expected channel hash table.\n");
   85 #ifdef SIDE_CHANNEL
   86     FileSSConfigInit();
   87 #endif
   88 }
   89 
   90 void file_resume_block_cleanup(void)
   91 {
   92     if (fileHash)
   93     {
   94         pthread_mutex_lock(&file_cache_mutex);
   95         sfxhash_delete(fileHash);
   96         fileHash = NULL;
   97         pthread_mutex_unlock(&file_cache_mutex);
   98     }
   99 #if defined (SIDE_CHANNEL) && defined (REG_TEST)
  100     FileCleanSS();
  101 #endif
  102 }
  103 
  104 static inline void updateFileNode(FileNode *node, File_Verdict verdict,
  105         uint32_t file_type_id, uint8_t *signature)
  106 {
  107     node->verdict = verdict;
  108     node->file_type_id = file_type_id;
  109     if (signature)
  110     {
  111         memcpy(node->sha256, signature, SHA256_HASH_SIZE);
  112     }
  113 }
  114 #ifdef SIDE_CHANNEL
  115 static int ProduceSSFileCache(FileHashKey *hk, FileNode *hv)
  116 {
  117     uint32_t offset = 0;
  118 
  119     void *msg_handle = NULL;
  120     void *hdr_ptr = NULL;
  121     void *data_ptr = NULL;
  122     if (!hk || !hv)
  123     {
  124         return -1;
  125     }
  126 
  127     if (CreateFileSSUpdate(&msg_handle, &hdr_ptr, &data_ptr, SC_MSG_TYPE_FILE_SS_HOST_CACHE, sizeof(*hk) + sizeof(*hv)) != 0)
  128     {
  129         FILE_ERROR("Side channel: Failed to create side channel update");
  130         return -1;
  131     }
  132 
  133     if (data_ptr)
  134     {
  135         memcpy(data_ptr, hk, sizeof(*hk));
  136         offset += sizeof(*hk);
  137 
  138         memcpy((uint8_t *)data_ptr + offset, hv, sizeof(*hv));
  139         offset += sizeof(*hv);
  140 
  141         SendFileSSUpdate(msg_handle, hdr_ptr, data_ptr, SC_MSG_TYPE_FILE_SS_HOST_CACHE, offset);
  142     }
  143 #ifdef REG_TEST
  144     LogMessage("produce verdict =%d file id =%d \n",hv->verdict,hv->file_type_id);
  145     file_sha256_print(hv->sha256);
  146 #endif
  147     FILE_DEBUG("Side channel: Produce verdict: %d, file id: %d",hv->verdict,hv->file_type_id);
  148     return 0;
  149 }
  150 
  151 int ConsumeSSFileCache(const uint8_t *buf, uint32_t len)
  152 {
  153     FileHashKey *hk;
  154     FileNode *hv;
  155     SFXHASH_NODE *hash_node;
  156     FileNode *node;
  157 
  158     if( !buf )
  159     {
  160         LogMessage("Side channel: No buffer\n");
  161         return -1;
  162     }
  163 
  164     if( len < sizeof(*hk) + sizeof(*hv) )
  165     {
  166         LogMessage("Side channel: length too small\n");
  167         return -1;
  168     }
  169     hk = (FileHashKey *)buf;
  170     hv = (FileNode *)(buf + sizeof(*hk));
  171 
  172     pthread_mutex_lock(&file_cache_mutex);
  173     hash_node = sfxhash_find_node(fileHash, hk);
  174     if (hash_node)
  175     {
  176       if (!(node = hash_node->data))
  177       {
  178         sfxhash_free_node(fileHash, hash_node);
  179       }
  180     }
  181     else
  182       node = NULL;
  183 
  184     if (node)
  185     {
  186       node->expires = hv->expires ;/* 20 minuts timeout*/
  187       updateFileNode(node, hv->verdict, hv->file_type_id, hv->sha256);
  188     }
  189     else if (sfxhash_add(fileHash, hk, hv) != SFXHASH_OK)
  190     {
  191       /* Uh, shouldn't get here...
  192        * There is already a node or couldn't alloc space
  193        * for key.  This means bigger problems, but fail
  194        * gracefully.
  195        */
  196       LogMessage("Failed to add file node to hash table\n");
  197       pthread_mutex_unlock(&file_cache_mutex);
  198       return -1;
  199     }
  200     pthread_mutex_unlock(&file_cache_mutex);
  201     LogMessage("consume verdict =%d file id =%d \n",hv->verdict,hv->file_type_id);
  202 #ifdef REG_TEST
  203     file_sha256_print(hv->sha256);
  204 #endif /* REG_TEST */
  205 
  206     return 0;
  207 }
  208 #endif
  209 
  210 /** *
  211  * @param sip - source IP address
  212  * @param dip - destination IP address
  213  * @param sport - server sport number
  214  * @param file_sig - file signature
  215  * @param expiry - session expiry in seconds.
  216  */
  217 int file_resume_block_add_file(void *pkt, uint32_t file_sig, uint32_t timeout,
  218         File_Verdict verdict, uint32_t file_type_id, uint8_t *signature, uint16_t cli_port, uint16_t srv_port, bool create_pinhole, bool direction)
  219 {
  220     FileHashKey hashKey;
  221     SFXHASH_NODE *hash_node = NULL;
  222     FileNode *node;
  223     FileNode new_node;
  224 #ifdef HAVE_DAQ_DP_ADD_DC
  225     bool use_other_port = false;
  226 #endif
  227     sfaddr_t* srcIP;
  228     sfaddr_t* dstIP;
  229     Packet *p = (Packet*)pkt;
  230     time_t now = p->pkth->ts.tv_sec;
  231     SAVE_DAQ_PKT_HDR(p);
  232 
  233     srcIP = GET_SRC_IP(p);
  234     dstIP = GET_DST_IP(p);
  235     sfaddr_copy_to_raw(&hashKey.dip, dstIP);
  236     sfaddr_copy_to_raw(&hashKey.sip, srcIP);
  237     hashKey.file_sig = file_sig;
  238 
  239     pthread_mutex_lock(&file_cache_mutex);
  240     hash_node = sfxhash_find_node(fileHash, &hashKey);
  241     if (hash_node)
  242     {
  243         if (!(node = hash_node->data))
  244         {
  245             sfxhash_free_node(fileHash, hash_node);
  246         }
  247     }
  248     else
  249         node = NULL;
  250     pthread_mutex_unlock(&file_cache_mutex);
  251 
  252     if ( timeout == 0  && verdict == 0 && file_type_id == 0)
  253     {
  254         FileConfig *file_config;
  255         FileContext *context;
  256         file_config =  (FileConfig *)(snort_conf->file_config);
  257         context = get_main_file_context(p->ssnptr);
  258         if (!context && !node)
  259         {
  260             FILE_ERROR("Resume block: context and node not found");
  261             return -1;
  262         }
  263         timeout = (uint32_t)file_config->file_block_timeout;
  264         if(context)
  265         {
  266         verdict = context->verdict;
  267         file_type_id = context->file_type_id;
  268         signature = context->sha256;
  269         }
  270         else
  271         {
  272             verdict = node->verdict;
  273             file_type_id = node->file_type_id;
  274             signature = node->sha256;
  275         }
  276 #ifdef HAVE_DAQ_DP_ADD_DC
  277         use_other_port = true;
  278 #endif
  279     }
  280 #ifdef HAVE_DAQ_DP_ADD_DC
  281     if (create_pinhole)
  282     {
  283         DAQ_DC_Params params;
  284 
  285         memset(&params, 0, sizeof(params));
  286         params.flags = DAQ_DC_ALLOW_MULTIPLE;
  287         params.timeout_ms = 5 * 60 * 1000; /* 5 minutes */
  288         if (p->packet_flags & PKT_FROM_CLIENT)
  289         {
  290             if(use_other_port)
  291             {
  292                 if(direction)
  293                     DAQ_Add_Dynamic_Protocol_Channel(p, srcIP, 0, dstIP, srv_port, GET_IPH_PROTO(p), &params);
  294                 else
  295                     DAQ_Add_Dynamic_Protocol_Channel(p, dstIP, 0, srcIP, srv_port, GET_IPH_PROTO(p), &params);
  296             }
  297             else
  298                 DAQ_Add_Dynamic_Protocol_Channel(p, srcIP, 0, dstIP, p->dp, GET_IPH_PROTO(p), &params);
  299             FILE_DEBUG("Pinhole created from client packet, direction: %d, time: %d",direction, now);
  300         }
  301         else if (p->packet_flags & PKT_FROM_SERVER)
  302         {
  303             if(use_other_port)
  304             {
  305                 if(direction)
  306                     DAQ_Add_Dynamic_Protocol_Channel(p, srcIP, 0, dstIP, srv_port, GET_IPH_PROTO(p), &params);
  307                 else
  308                     DAQ_Add_Dynamic_Protocol_Channel(p, dstIP, 0, srcIP, srv_port, GET_IPH_PROTO(p), &params);
  309             }
  310             else
  311                 DAQ_Add_Dynamic_Protocol_Channel(p, dstIP, 0, srcIP, p->sp, GET_IPH_PROTO(p), &params);
  312             FILE_DEBUG("Pinhole created from server packet, direction: %d, time: %d",direction, now);
  313         }
  314     }
  315 #endif
  316 
  317     if (node)
  318     {
  319         FILE_DEBUG("Resume block: Updating file node");
  320         node->expires = now + (timeout * 4);/* 20 minuts timeout*/
  321         updateFileNode(node, verdict, file_type_id, signature);
  322 #ifdef SIDE_CHANNEL
  323         if (ProduceSSFileCache(&hashKey, node) < 0)
  324         {
  325           LogMessage("Failed to add Side channel message\n");
  326         }
  327 #endif
  328     }
  329     else
  330     {
  331 
  332         FILE_DEBUG("Resume block: Adding file node");
  333 
  334         updateFileNode(&new_node, verdict, file_type_id, signature);
  335 
  336         /*
  337          * use the time that we keep files around
  338          * since this info would effectively be invalid
  339          * after that anyway because the file that
  340          * caused this will be gone.
  341          */
  342         new_node.expires = now + (timeout * 4);/* 20 minuts timeout*/
  343 
  344         /* Add it to the table */
  345 #ifdef SIDE_CHANNEL
  346         if (ProduceSSFileCache(&hashKey, &new_node) < 0)
  347         {
  348           LogMessage("Failed to add Side channel message\n");
  349         }
  350 #endif
  351         pthread_mutex_lock(&file_cache_mutex);
  352         if (sfxhash_add(fileHash, &hashKey, &new_node) != SFXHASH_OK)
  353         {
  354             /* Uh, shouldn't get here...
  355              * There is already a node or couldn't alloc space
  356              * for key.  This means bigger problems, but fail
  357              * gracefully.
  358              */
  359             FILE_ERROR("Resume block: Failed to add file node to hash table");
  360             pthread_mutex_unlock(&file_cache_mutex);
  361             return -1;
  362         }
  363         pthread_mutex_unlock(&file_cache_mutex);
  364     }
  365     if (signature)
  366     {
  367         FILE_DEBUG("Resume block: Added file node with verdict: %d, file signature: %d, hash:"
  368                 "%02X%02X %02X%02X %02X%02X %02X%02X" 
  369                 "%02X%02X %02X%02X %02X%02X %02X%02X "
  370                 "%02X%02X %02X%02X %02X%02X %02X%02X "
  371                 "%02X%02X %02X%02X %02X%02X %02X%02X",
  372                 verdict, file_sig,
  373                 signature[0], signature[1], signature[2], signature[3],
  374                 signature[4], signature[5], signature[6], signature[7],
  375                 signature[8], signature[9], signature[10], signature[11],
  376                 signature[12], signature[13], signature[14], signature[15],
  377                 signature[16], signature[17], signature[18], signature[19],
  378                 signature[20], signature[21], signature[22], signature[23],
  379                 signature[24], signature[25], signature[26], signature[27],
  380                 signature[28], signature[29], signature[30], signature[31]);
  381     }
  382     else
  383     {
  384         FILE_DEBUG("Resume block: Added file node with verdict: %d, file signature: %d",
  385                 verdict, file_sig);
  386     }
  387     return 0;
  388 }
  389 
  390 static inline File_Verdict checkVerdict(Packet *p, FileNode *node, SFXHASH_NODE *hash_node)
  391 {
  392     File_Verdict verdict = FILE_VERDICT_UNKNOWN;
  393     FileContext *context = NULL;
  394     bool partialFile = false;
  395 
  396     /*Query the file policy in case verdict has been changed*/
  397     /*Check file type first*/
  398     if (cur_config.file_type_cb)
  399     {
  400         verdict = cur_config.file_type_cb(p, p->ssnptr, node->file_type_id, 0,
  401                 DEFAULT_FILE_ID);
  402         FILE_DEBUG("Checking verdict, node verdict: %d, file type verdict: %d",node->verdict, verdict);
  403     }
  404 
  405     if ((verdict == FILE_VERDICT_UNKNOWN) ||
  406             (verdict == FILE_VERDICT_STOP_CAPTURE))
  407     {
  408         if (cur_config.file_signature_cb)
  409         {
  410             context = get_main_file_context(p->ssnptr);
  411             if(NULL != context)
  412             {
  413                 partialFile = context->partial_file;
  414             }
  415             verdict = cur_config.file_signature_cb(p, p->ssnptr, node->sha256, 0,
  416                     &sig_file_state, 0, DEFAULT_FILE_ID, partialFile );
  417             FILE_DEBUG("Checking verdict, node verdict: %d, file signature verdict: %d",node->verdict, verdict);
  418         }
  419     }
  420 
  421     if ((verdict == FILE_VERDICT_UNKNOWN) ||
  422             (verdict == FILE_VERDICT_STOP_CAPTURE))
  423     {
  424         verdict = node->verdict;
  425     }
  426 
  427     if (verdict == FILE_VERDICT_LOG)
  428     {
  429         pthread_mutex_lock(&file_cache_mutex);
  430         sfxhash_free_node(fileHash, hash_node);
  431         pthread_mutex_unlock(&file_cache_mutex);
  432         if (cur_config.log_file_action)
  433         {
  434             cur_config.log_file_action(p->ssnptr, FILE_RESUME_LOG);
  435         }
  436     }
  437     else if (verdict == FILE_VERDICT_BLOCK)
  438     {
  439         Active_ForceDropPacket();
  440         Active_DropSession(p);
  441         if (cur_config.log_file_action)
  442         {
  443             cur_config.log_file_action(p->ssnptr, FILE_RESUME_BLOCK);
  444         }
  445         node->verdict = verdict;
  446     }
  447     else if (verdict == FILE_VERDICT_REJECT)
  448     {
  449         Active_ForceDropPacket();
  450         Active_DropSession(p);
  451 #ifdef ACTIVE_RESPONSE
  452         Active_QueueReject();
  453 #endif
  454         if (cur_config.log_file_action)
  455         {
  456             cur_config.log_file_action(p->ssnptr, FILE_RESUME_BLOCK);
  457         }
  458         node->verdict = verdict;
  459     }
  460     else if (verdict == FILE_VERDICT_PENDING)
  461     {
  462         /*Take the cached verdict*/
  463         Active_ForceDropPacket();
  464         Active_DropSession(p);
  465 #ifdef ACTIVE_RESPONSE
  466         if (FILE_VERDICT_REJECT == node->verdict)
  467             Active_QueueReject();
  468 #endif
  469         if (cur_config.log_file_action)
  470         {
  471             cur_config.log_file_action(p->ssnptr, FILE_RESUME_BLOCK);
  472         }
  473         verdict = node->verdict;
  474     }
  475     FILE_DEBUG("Verdict checked for file node with hash: " 
  476             "%02X%02X %02X%02X %02X%02X %02X%02X" 
  477             "%02X%02X %02X%02X %02X%02X %02X%02X "
  478             "%02X%02X %02X%02X %02X%02X %02X%02X "
  479             "%02X%02X %02X%02X %02X%02X %02X%02X",
  480             node->sha256[0], node->sha256[1], node->sha256[2], node->sha256[3],
  481             node->sha256[4], node->sha256[5], node->sha256[6], node->sha256[7],
  482             node->sha256[8], node->sha256[9], node->sha256[10], node->sha256[11],
  483             node->sha256[12], node->sha256[13], node->sha256[14], node->sha256[15],
  484             node->sha256[16], node->sha256[17], node->sha256[18], node->sha256[19],
  485             node->sha256[20], node->sha256[21], node->sha256[22], node->sha256[23],
  486             node->sha256[24], node->sha256[25], node->sha256[26], node->sha256[27],
  487             node->sha256[28], node->sha256[29], node->sha256[30], node->sha256[31]);
  488 
  489     return verdict;
  490 }
  491 
  492 File_Verdict file_resume_block_check(void *pkt, uint32_t file_sig)
  493 {
  494     File_Verdict verdict = FILE_VERDICT_UNKNOWN;
  495     sfaddr_t* srcIP;
  496     sfaddr_t* dstIP;
  497     SFXHASH_NODE *hash_node;
  498     FileHashKey hashKey;
  499     FileNode *node;
  500     Packet *p = (Packet*)pkt;
  501     SAVE_DAQ_PKT_HDR(pkt);
  502 
  503     /* No hash table, or its empty?  Get out of dodge.  */
  504     if (!fileHash || !sfxhash_count(fileHash))
  505     {
  506         FILE_DEBUG("No expected sessions");
  507         return verdict;
  508     }
  509 
  510     srcIP = GET_SRC_IP(p);
  511     dstIP = GET_DST_IP(p);
  512     sfaddr_copy_to_raw(&hashKey.dip, dstIP);
  513     sfaddr_copy_to_raw(&hashKey.sip, srcIP);
  514     hashKey.file_sig = file_sig;
  515 
  516     pthread_mutex_lock(&file_cache_mutex);
  517     hash_node = sfxhash_find_node(fileHash, &hashKey);
  518   
  519     if (hash_node)
  520     {
  521         if (!(node = hash_node->data))
  522         {
  523             sfxhash_free_node(fileHash, hash_node);
  524         }
  525     }
  526     else
  527     {
  528         pthread_mutex_unlock(&file_cache_mutex);
  529         FILE_DEBUG("File not found");
  530         return verdict;
  531     }
  532     pthread_mutex_unlock(&file_cache_mutex);
  533 
  534     if (node)
  535     {
  536         FILE_DEBUG("Found resumed file");
  537         if (node->expires && p->pkth->ts.tv_sec > node->expires)
  538         {
  539             FILE_DEBUG("File expired, verdict: %d",verdict);
  540             pthread_mutex_lock(&file_cache_mutex);
  541             sfxhash_free_node(fileHash, hash_node);
  542             pthread_mutex_unlock(&file_cache_mutex);
  543             return verdict;
  544         }
  545         /*Query the file policy in case verdict has been changed*/
  546         verdict = checkVerdict(p, node, hash_node);
  547     }
  548     if (verdict == FILE_VERDICT_BLOCK || verdict == FILE_VERDICT_REJECT || verdict == FILE_VERDICT_PENDING)
  549     {
  550         if (pkt_trace_enabled)
  551             addPktTraceData(VERDICT_REASON_FILE, snprintf(trace_line, MAX_TRACE_LINE,
  552                 "File Process: file not resumed, %s\n", getPktTraceActMsg()));
  553         else addPktTraceData(VERDICT_REASON_FILE, 0);
  554         FILE_INFO("File not resumed, verdict: %d",verdict);
  555     }
  556     else
  557         FILE_INFO("File resumed, verdict: %d",verdict);
  558     return verdict;
  559 }