"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/preprocessors/Stream6/snort_stream_icmp.c" (16 Oct 2020, 11844 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 "snort_stream_icmp.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  *
    3  * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4  * Copyright (C) 2004-2013 Sourcefire, Inc.
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License Version 2 as
    8  * published by the Free Software Foundation.  You may not use, modify or
    9  * distribute this program under any other version of the GNU General
   10  * Public License.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   20  *
   21  ****************************************************************************/
   22 
   23 #ifdef HAVE_CONFIG_H
   24 #include "config.h"
   25 #endif
   26 
   27 #include "sf_types.h"
   28 #include "snort_debug.h"
   29 #include "decode.h"
   30 #include "mstring.h"
   31 #include "sfxhash.h"
   32 #include "util.h"
   33 
   34 #include "spp_session.h"
   35 #include "session_api.h"
   36 #include "snort_session.h"
   37 
   38 #include "stream_common.h"
   39 #include "snort_stream_tcp.h"
   40 #include "snort_stream_udp.h"
   41 #include "snort_stream_icmp.h"
   42 
   43 #include "parser.h"
   44 
   45 #include "reg_test.h"
   46 
   47 #include "profiler.h"
   48 #include "sfPolicy.h"
   49 #ifdef PERF_PROFILING
   50 PreprocStats s5IcmpPerfStats;
   51 #endif
   52 
   53 /* client/server ip/port dereference */
   54 #define icmp_sender_ip lwSsn->client_ip
   55 #define icmp_responder_ip lwSsn->server_ip
   56 
   57 /*  D A T A  S T R U C T U R E S  ***********************************/
   58 typedef struct _IcmpSession
   59 {
   60     SessionControlBlock *lwSsn;
   61 
   62     uint32_t   echo_count;
   63 
   64     struct timeval ssn_time;
   65 
   66 } IcmpSession;
   67 
   68 
   69 /*  G L O B A L S  **************************************************/
   70 static SessionCache* icmp_lws_cache = NULL;
   71 
   72 /*  P R O T O T Y P E S  ********************************************/
   73 static void StreamParseIcmpArgs(char *, StreamIcmpPolicy *);
   74 static void StreamPrintIcmpConfig(StreamIcmpPolicy *);
   75 static int ProcessIcmpUnreach(Packet *p);
   76 static int ProcessIcmpEcho(Packet *p);
   77 
   78 void StreamInitIcmp( void )
   79 {
   80     /* Finally ICMP */
   81     if(icmp_lws_cache == NULL)
   82     {
   83         icmp_lws_cache = session_api->init_session_cache( SESSION_PROTO_ICMP,
   84                                                           sizeof( IcmpSession ),
   85                                                           NULL );
   86     }
   87 }
   88 
   89 void StreamIcmpPolicyInit(StreamIcmpConfig *config, char *args)
   90 {
   91     if (config == NULL)
   92         return;
   93 
   94     config->num_policies++;
   95 
   96     StreamParseIcmpArgs(args, &config->default_policy);
   97 
   98     StreamPrintIcmpConfig(&config->default_policy);
   99 }
  100 
  101 static void StreamParseIcmpArgs(char *args, StreamIcmpPolicy *s5IcmpPolicy)
  102 {
  103     char **toks;
  104     int num_toks;
  105     int i;
  106     char **stoks = NULL;
  107     int s_toks;
  108     char *endPtr = NULL;
  109 
  110     s5IcmpPolicy->session_timeout = STREAM_DEFAULT_SSN_TIMEOUT;
  111     //s5IcmpPolicy->flags = 0;
  112 
  113     if(args != NULL && strlen(args) != 0)
  114     {
  115         toks = mSplit(args, ",", 0, &num_toks, 0);
  116 
  117         for (i = 0; i < num_toks; i++)
  118         {
  119             stoks = mSplit(toks[i], " ", 2, &s_toks, 0);
  120 
  121             if (s_toks == 0)
  122             {
  123                 FatalError("%s(%d) => Missing parameter in Stream ICMP config.\n",
  124                     file_name, file_line);
  125             }
  126 
  127             if(!strcasecmp(stoks[0], "timeout"))
  128             {
  129                 if(stoks[1])
  130                 {
  131                     s5IcmpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10);
  132                 }
  133 
  134                 if (!stoks[1] || (endPtr == &stoks[1][0]) || *endPtr)
  135                 {
  136                     FatalError("%s(%d) => Invalid timeout in config file.  Integer parameter required.\n",
  137                             file_name, file_line);
  138                 }
  139 
  140                 if ((s5IcmpPolicy->session_timeout > STREAM_MAX_SSN_TIMEOUT) ||
  141                     (s5IcmpPolicy->session_timeout < STREAM_MIN_SSN_TIMEOUT))
  142                 {
  143                     FatalError("%s(%d) => Invalid timeout in config file.  "
  144                         "Must be between %d and %d\n",
  145                         file_name, file_line,
  146                         STREAM_MIN_SSN_TIMEOUT, STREAM_MAX_SSN_TIMEOUT);
  147                 }
  148                 if (s_toks > 2)
  149                 {
  150                     FatalError("%s(%d) => Invalid Stream ICMP Policy option.  Missing comma?\n",
  151                         file_name, file_line);
  152                 }
  153             }
  154             else
  155             {
  156                 FatalError("%s(%d) => Invalid Stream ICMP policy option\n",
  157                             file_name, file_line);
  158             }
  159 
  160             mSplitFree(&stoks, s_toks);
  161         }
  162 
  163         mSplitFree(&toks, num_toks);
  164     }
  165 }
  166 
  167 static void StreamPrintIcmpConfig(StreamIcmpPolicy *s5IcmpPolicy)
  168 {
  169     LogMessage("Stream ICMP Policy config:\n");
  170     LogMessage("    Timeout: %d seconds\n", s5IcmpPolicy->session_timeout);
  171     //LogMessage("    Flags: 0x%X\n", s5UdpPolicy->flags);
  172     //IpAddrSetPrint("    Bound Addresses:", s5UdpPolicy->bound_addrs);
  173 
  174 }
  175 
  176 void IcmpSessionCleanup(SessionControlBlock *ssn)
  177 {
  178     IcmpSession *icmpssn = NULL;
  179 
  180     if (ssn->ha_state.session_flags & SSNFLAG_PRUNED)
  181     {
  182         CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED);
  183     }
  184     else if (ssn->ha_state.session_flags & SSNFLAG_TIMEDOUT)
  185     {
  186         CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT);
  187     }
  188     else
  189     {
  190         CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY);
  191     }
  192 
  193     if (ssn->proto_specific_data)
  194         icmpssn = ssn->proto_specific_data->data;
  195 
  196     if (!icmpssn)
  197     {
  198         /* Huh? */
  199         return;
  200     }
  201 
  202     /* Cleanup the proto specific data */
  203     session_api->free_protocol_session_pool( SESSION_PROTO_ICMP, ssn );
  204     ssn->proto_specific_data = NULL;
  205 
  206     StreamResetFlowBits(ssn);
  207     session_api->free_application_data(ssn);
  208 
  209     s5stats.icmp_sessions_released++;
  210     s5stats.active_icmp_sessions--;
  211 }
  212 
  213 uint32_t StreamGetIcmpPrunes(void)
  214 {
  215     if( icmp_lws_cache )
  216         return session_api->get_session_prune_count( SESSION_PROTO_ICMP );
  217     else
  218         return s5stats.icmp_prunes;
  219 }
  220 
  221 void StreamResetIcmpPrunes(void)
  222 {
  223     session_api->reset_session_prune_count( SESSION_PROTO_ICMP );
  224 }
  225 
  226 void StreamResetIcmp(void)
  227 {
  228     session_api->purge_session_cache(icmp_lws_cache);
  229     session_api->clean_protocol_session_pool( SESSION_PROTO_ICMP );
  230 }
  231 
  232 void StreamCleanIcmp(void)
  233 {
  234     if ( icmp_lws_cache )
  235         s5stats.icmp_prunes = session_api->get_session_prune_count( SESSION_PROTO_ICMP );
  236 
  237     /* Clean up session cache */
  238     session_api->delete_session_cache( SESSION_PROTO_ICMP );
  239     icmp_lws_cache = NULL;
  240 }
  241 
  242 void StreamIcmpConfigFree(StreamIcmpConfig *config)
  243 {
  244     if (config == NULL)
  245         return;
  246 
  247     free(config);
  248 }
  249 
  250 int StreamVerifyIcmpConfig(StreamIcmpConfig *config, tSfPolicyId policy_id)
  251 {
  252     if (config == NULL)
  253         return -1;
  254 
  255     if (!icmp_lws_cache)
  256         return -1;
  257 
  258     if (config->num_policies == 0)
  259         return -1;
  260 
  261     return 0;
  262 }
  263 
  264 int StreamProcessIcmp(Packet *p)
  265 {
  266     int status;
  267 
  268     switch (p->icmph->type)
  269     {
  270     case ICMP_DEST_UNREACH:
  271         status = ProcessIcmpUnreach(p);
  272         break;
  273 
  274     case ICMP_ECHO:
  275     case ICMP_ECHOREPLY:
  276         status = ProcessIcmpEcho(p);
  277         break;
  278 
  279     default:
  280         /* We only handle the above ICMP messages with stream5 */
  281         status = 0;
  282         break;
  283     }
  284 
  285     return status;
  286 }
  287 
  288 static int ProcessIcmpUnreach(Packet *p)
  289 {
  290     /* Handle ICMP unreachable */
  291     SessionKey skey;
  292     SessionControlBlock *ssn = NULL;
  293     uint16_t sport;
  294     uint16_t dport;
  295     sfaddr_t *src;
  296     sfaddr_t *dst;
  297 
  298     /* No "orig" IP Header */
  299     if (!p->orig_iph)
  300         return 0;
  301 
  302     /* Get TCP/UDP/ICMP session from original protocol/port info
  303      * embedded in the ICMP Unreach message.  This is already decoded
  304      * in p->orig_foo.  TCP/UDP ports are decoded as p->orig_sp/dp.
  305      */
  306     skey.protocol = GET_ORIG_IPH_PROTO(p);
  307     sport = p->orig_sp;
  308     dport = p->orig_dp;
  309 
  310     src = GET_ORIG_SRC(p);
  311     dst = GET_ORIG_DST(p);
  312 
  313     if (sfip_fast_lt6(src, dst))
  314     {
  315         COPY4(skey.ip_l, sfaddr_get_ip6_ptr(src));
  316         skey.port_l = sport;
  317         COPY4(skey.ip_h, sfaddr_get_ip6_ptr(dst));
  318         skey.port_h = dport;
  319     }
  320     else if (IP_EQUALITY(src, dst))
  321     {
  322         COPY4(skey.ip_l, sfaddr_get_ip6_ptr(src));
  323         COPY4(skey.ip_h, skey.ip_l);
  324         if (sport < dport)
  325         {
  326             skey.port_l = sport;
  327             skey.port_h = dport;
  328         }
  329         else
  330         {
  331             skey.port_l = dport;
  332             skey.port_h = sport;
  333         }
  334     }
  335     else
  336     {
  337         COPY4(skey.ip_l, sfaddr_get_ip6_ptr(dst));
  338         COPY4(skey.ip_h, sfaddr_get_ip6_ptr(src));
  339         skey.port_l = dport;
  340         skey.port_h = sport;
  341     }
  342 
  343     if (p->vh)
  344         skey.vlan_tag = (uint16_t)VTH_VLAN(p->vh);
  345     else
  346         skey.vlan_tag = 0;
  347 
  348     switch (skey.protocol)
  349     {
  350     case IPPROTO_TCP:
  351         /* Lookup a TCP session */
  352         ssn = GetLWTcpSession(&skey);
  353         break;
  354     case IPPROTO_UDP:
  355         /* Lookup a UDP session */
  356         ssn = GetLWUdpSession(&skey);
  357         break;
  358     case IPPROTO_ICMP:
  359         /* Lookup a ICMP session */
  360         ssn = session_api->get_session_by_key(icmp_lws_cache, &skey);
  361         break;
  362     }
  363 
  364     if (ssn)
  365     {
  366         /* Mark this session as dead. */
  367         DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
  368             "Marking session as dead, per ICMP Unreachable!\n"););
  369         ssn->ha_state.session_flags |= SSNFLAG_DROP_CLIENT;
  370         ssn->ha_state.session_flags |= SSNFLAG_DROP_SERVER;
  371         ssn->session_state |= STREAM_STATE_UNREACH;
  372         s5stats.active_icmp_sessions++;
  373     }
  374 
  375     return 0;
  376 }
  377 
  378 static int ProcessIcmpEcho(Packet *p)
  379 {
  380     //SessionKey skey;
  381     //SessionControlBlock *ssn = NULL;
  382     s5stats.active_icmp_sessions++;
  383 
  384     return 0;
  385 }
  386 
  387 void IcmpUpdateDirection(SessionControlBlock *ssn, char dir, sfaddr_t* ip, uint16_t port)
  388 {
  389     IcmpSession *icmpssn = ssn->proto_specific_data->data;
  390     sfaddr_t tmpIp;
  391 
  392     if (!icmpssn)
  393     {
  394         /* Huh? */
  395         return;
  396     }
  397 
  398     if (IP_EQUALITY(&icmpssn->icmp_sender_ip, ip))
  399     {
  400         if ((dir == SSN_DIR_FROM_SENDER) && (ssn->ha_state.direction == SSN_DIR_FROM_SENDER))
  401         {
  402             /* Direction already set as SENDER */
  403             return;
  404         }
  405     }
  406     else if (IP_EQUALITY(&icmpssn->icmp_responder_ip, ip))
  407     {
  408         if ((dir == SSN_DIR_FROM_RESPONDER) && (ssn->ha_state.direction == SSN_DIR_FROM_RESPONDER))
  409         {
  410             /* Direction already set as RESPONDER */
  411             return;
  412         }
  413     }
  414 
  415     /* Swap them -- leave ssn->ha_state.direction the same */
  416     tmpIp = icmpssn->icmp_sender_ip;
  417     icmpssn->icmp_sender_ip = icmpssn->icmp_responder_ip;
  418     icmpssn->icmp_responder_ip = tmpIp;
  419 }
  420 
  421 #ifdef SNORT_RELOAD
  422 void SessionICMPReload(uint32_t max_sessions, uint16_t pruningTimeout, uint16_t nominalTimeout)
  423 {
  424     SessionReload(icmp_lws_cache, max_sessions, pruningTimeout, nominalTimeout
  425 #ifdef REG_TEST
  426                   , "ICMP"
  427 #endif
  428                   );
  429 }
  430 
  431 unsigned SessionICMPReloadAdjust(unsigned maxWork)
  432 {
  433     return SessionProtocolReloadAdjust(icmp_lws_cache, session_configuration->max_icmp_sessions, 
  434                                        maxWork, 0
  435 #ifdef REG_TEST
  436                                        , "ICMP"
  437 #endif
  438                                        );
  439 }
  440 #endif
  441 
  442 size_t get_icmp_used_mempool()
  443 {
  444     if (icmp_lws_cache && icmp_lws_cache->protocol_session_pool)
  445         return icmp_lws_cache->protocol_session_pool->used_memory;
  446 
  447     return 0;
  448 }