1 /****************************************************************************
2  *
3  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4  * Copyright (C) 2006-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 /*
24  ** ppm.h  - packet performance monitor
25  **
26  ** Author: Marc Norton <mnorton@sourcefire.com>
27  **
28  */
29 
30 #ifndef __PACKET_PROCESSING_MONITOR_H__
31 #define __PACKET_PROCESSING_MONITOR_H__
32 
33 #ifdef PPM_MGR
34 
35 #include "sf_types.h"
36 #include "cpuclock.h"
37 
38 #define cputime get_clockticks
39 
40 typedef uint64_t PPM_TICKS;
41 typedef uint64_t PPM_USECS;
42 typedef unsigned int PPM_SECS;
43 
44 struct _SnortConfig;
45 
46 extern struct _SnortConfig *snort_conf;
47 
48 typedef struct
49 {
50     /* config section */
51     int enabled;
52 
53     PPM_TICKS max_pkt_ticks;
54     int pkt_log;     /* alert,console,syslog */
55     int pkt_action;  /* suspend */
56 
57     PPM_TICKS max_rule_ticks;
58     uint64_t rule_threshold; /* rules must fail this many times in a row to suspend */
59 
60     int rule_log;    /* alert,console,syslog */
61     int rule_action; /* suspend */
62 
63 #ifdef DEBUG
64     int debug_pkts;
65     int debug_rules;
66 #endif
67 
68     /* stats section */
69     unsigned int rule_event_cnt;
70     unsigned int pkt_event_cnt;
71 
72     uint64_t   tot_pkt_time; /* ticks */
73     uint64_t   tot_pkts;
74 
75     uint64_t   tot_rule_time; /* ticks */
76     uint64_t   tot_rules;
77 
78     uint64_t   tot_nc_rule_time; /* ticks */
79     uint64_t   tot_nc_rules;
80 
81     uint64_t   tot_pcre_rule_time; /* ticks */
82     uint64_t   tot_pcre_rules;
83 
84     uint64_t   max_suspend_ticks;
85 
86 } ppm_cfg_t;
87 
88 typedef struct
89 {
90     uint64_t   pktcnt;
91     uint64_t   start, cur, tot;
92     uint64_t   subtract;
93     PPM_TICKS max_pkt_ticks;
94     unsigned int rule_tests;
95     unsigned int pcre_rule_tests;
96     unsigned int nc_rule_tests;
97 
98 } ppm_pkt_timer_t;
99 
100 typedef struct
101 {
102     uint64_t start, cur, tot;
103     PPM_TICKS max_rule_ticks;
104 
105 } ppm_rule_timer_t;
106 
107 /* global data */
108 #define PPM_MAX_TIMERS 10
109 extern PPM_TICKS ppm_tpu;
110 extern ppm_pkt_timer_t   ppm_pkt_times[PPM_MAX_TIMERS];
111 extern ppm_pkt_timer_t  *ppm_pt;
112 extern unsigned int      ppm_pkt_index;
113 extern ppm_rule_timer_t  ppm_rule_times[PPM_MAX_TIMERS];
114 extern ppm_rule_timer_t *ppm_rt;
115 extern unsigned int      ppm_rule_times_index;
116 extern uint64_t            ppm_cur_time;
117 extern int ppm_abort_this_pkt;
118 extern int ppm_suspend_this_rule;
119 
120 #define PPM_LOG_ALERT      1
121 #define PPM_LOG_MESSAGE    2
122 #define PPM_ACTION_SUSPEND 1
123 
124 /* Config flags */
125 #define PPM_ENABLED()                 (snort_conf->ppm_cfg.enabled > 0)
126 #define PPM_PKTS_ENABLED()            (snort_conf->ppm_cfg.max_pkt_ticks > 0)
127 #define PPM_RULES_ENABLED()           (snort_conf->ppm_cfg.max_rule_ticks > 0)
128 
129 /* packet, rule event flags */
130 #define PPM_PACKET_ABORT_FLAG()       ppm_abort_this_pkt
131 #define PPM_RULE_SUSPEND_FLAG()       ppm_suspend_this_rule
132 
133 #define PPM_INC_PKT_CNT()         snort_conf->ppm_cfg.tot_pkts++
134 #define PPM_PKT_CNT()             ppm_pt->pktcnt
135 #define PPM_PKT_LOG(p)            if (ppm_abort_this_pkt) ppm_pkt_log(&snort_conf->ppm_cfg,p)
136 #define PPM_RULE_LOG(cnt,p)       ppm_rule_log(&snort_conf->ppm_cfg,cnt,p)
137 #define PPM_ACCUM_PKT_TIME()      snort_conf->ppm_cfg.tot_pkt_time += ppm_pt->tot;
138 #define PPM_ACCUM_RULE_TIME() \
139     snort_conf->ppm_cfg.tot_rule_time += ppm_rt->tot; \
140     snort_conf->ppm_cfg.tot_rules++;
141 #define PPM_ACCUM_NC_RULE_TIME() \
142     snort_conf->ppm_cfg.tot_nc_rule_time += ppm_rt->tot; \
143     snort_conf->ppm_cfg.tot_nc_rules++;
144 #define PPM_ACCUM_PCRE_RULE_TIME() \
145     snort_conf->ppm_cfg.tot_pcre_rule_time += ppm_rt->tot; \
146     snort_conf->ppm_cfg.tot_pcre_rules++;
147 #define PPM_GET_TIME()             cputime(ppm_cur_time)
148 #define PPM_PKT_RULE_TESTS()       ppm_pt->rule_tests
149 #define PPM_PKT_PCRE_RULE_TESTS()  ppm_pt->pcre_rule_tests
150 #define PPM_PKT_NC_RULE_TESTS()    ppm_pt->nc_rule_tests
151 #define PPM_INC_PKT_RULE_TESTS()      if(ppm_pt)ppm_pt->rule_tests++
152 #define PPM_INC_PKT_PCRE_RULE_TESTS() if(ppm_pt)ppm_pt->pcre_rule_tests++
153 #define PPM_INC_PKT_NC_RULE_TESTS()   if(ppm_pt)ppm_pt->nc_rule_tests++
154 #ifdef DEBUG
155 #define PPM_DEBUG_PKTS()           snort_conf->ppm_cfg.debug_pkts
156 #endif
157 
158 #define PPM_PRINT_PKT_TIME(a)    LogMessage(a, ppm_ticks_to_usecs((PPM_TICKS)ppm_pt->tot) );
159 
160 #ifdef PPM_TEST
161 /* use usecs instead of ticks for rule suspension during pcap playback */
162 #define PPM_RULE_TIME(p) ((p->pkth->ts.tv_sec * 1000000) + p->pkth->ts.tv_usec)
163 #else
164 #define PPM_RULE_TIME(p) ppm_cur_time
165 #endif
166 
167 #define PPM_INIT_PKT_TIMER() \
168     if(ppm_pkt_index < PPM_MAX_TIMERS) \
169 { \
170     ppm_pt = &ppm_pkt_times[ppm_pkt_index++]; \
171     ppm_abort_this_pkt = 0; \
172     ppm_pt->pktcnt = snort_conf->ppm_cfg.tot_pkts; \
173     ppm_pt->start = ppm_cur_time; \
174     ppm_pt->subtract = 0; \
175     ppm_pt->rule_tests = 0; \
176     ppm_pt->pcre_rule_tests = 0; \
177     ppm_pt->nc_rule_tests = 0; \
178     ppm_pt->max_pkt_ticks = snort_conf->ppm_cfg.max_pkt_ticks; \
179     ppm_init_rules(); \
180 }
181 
182 #define PPM_TOTAL_PKT_TIME() \
183     if( ppm_pt) \
184 { \
185     ppm_pt->tot = ppm_cur_time - ppm_pt->start - ppm_pt->subtract; \
186 }
187 
188 #define PPM_END_PKT_TIMER() \
189     if( (ppm_pkt_index > 0)  && ppm_pt) \
190 { \
191     ppm_pkt_index--; \
192     if( ppm_pkt_index > 0 ) \
193     { \
194         /*ppm_pkt_times[ppm_pkt_index-1].subtract=ppm_pt->tot; */ \
195         ppm_pt = &ppm_pkt_times[ppm_pkt_index-1]; \
196     } \
197     else \
198     { \
199         ppm_pt=0; \
200     } \
201 }
202 
203 #define PPM_INIT_RULE_TIMER() \
204     if(ppm_rule_times_index < PPM_MAX_TIMERS) \
205 { \
206     ppm_rt = &ppm_rule_times[ppm_rule_times_index++]; \
207     ppm_suspend_this_rule = 0; \
208     ppm_rt->start=ppm_cur_time; \
209     ppm_rt->max_rule_ticks = snort_conf->ppm_cfg.max_rule_ticks; \
210 }
211 
212 #define PPM_END_RULE_TIMER() \
213     if(( ppm_rule_times_index > 0) && ppm_rt ) \
214 { \
215     ppm_rule_times_index--; \
216     if (ppm_rule_times_index > 0) \
217     { \
218         ppm_rt=&ppm_rule_times[ppm_rule_times_index-1]; \
219     } else { \
220         ppm_rt=NULL; \
221     } \
222 }
223 
224 /* To print the log if ppm is enabled and ppm_abort_this_pkt is 1 */
225 #define PPM_LATENCY_TRACE() \
226     if( ppm_abort_this_pkt ) \
227     { \
228         if( pkt_trace_enabled ) \
229         { \
230             if( !PacketIsRebuilt(p)) \
231             { \
232                 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \
233                 "PL flag : (1)")); \
234             } \
235             else \
236             { \
237                 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \
238                 "PL/R flag : (1)")); \
239             } \
240         } \
241     } \
242 
243 /* use PPM_GET_TIME; first to get the current time */
244 #define PPM_PACKET_TEST() \
245     if( ppm_pt ) \
246 { \
247     ppm_pt->tot = ppm_cur_time - ppm_pt->start /*- ppm_pt->subtract*/; \
248     if(ppm_pt->tot > ppm_pt->max_pkt_ticks) \
249     { \
250         if( snort_conf->ppm_cfg.pkt_action & PPM_ACTION_SUSPEND ) \
251             ppm_abort_this_pkt = 1; \
252     } \
253 }
254 
255 #if 0 && defined(PPM_TEST)
256 #define PPM_DBG_CSV(state, otn, when) \
257     LogMessage( \
258                 "PPM, %u, %u, %s, " STDu64 "\n", \
259                 otn->sigInfo.generator, otn->sigInfo.id, state, when \
260               )
261 #else
262 #define PPM_DBG_CSV(state, otn, when)
263 #endif
264 
265 /* use PPM_GET_TIME; first to get the current time */
266 #define PPM_RULE_TEST(root,p) \
267     if( ppm_rt ) \
268 { \
269     ppm_rt->tot = ppm_cur_time - ppm_rt->start; \
270     if(ppm_rt->tot > ppm_rt->max_rule_ticks) \
271     { \
272         if( snort_conf->ppm_cfg.rule_action & PPM_ACTION_SUSPEND ) \
273         { \
274             int ii; \
275             ppm_suspend_this_rule = 1; \
276             (root)->ppm_disable_cnt++; \
277             if( pkt_trace_enabled ) \
278             { \
279                 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \
280                 "RL flag : (1)")); \
281             } \
282             for ( ii = 0; ii< root->num_children; ii++) \
283             { \
284                 root->children[ii]->ppm_disable_cnt++; \
285             } \
286             if( (root)->ppm_disable_cnt >= snort_conf->ppm_cfg.rule_threshold ) \
287             { \
288                 ppm_set_rule_event(&snort_conf->ppm_cfg, root); \
289                 (root)->tree_state=RULE_STATE_DISABLED; \
290                 (root)->ppm_suspend_time=PPM_RULE_TIME(p); \
291                 PPM_DBG_CSV("disabled", (root), (root)->ppm_suspend_time); \
292             } \
293             else \
294             { \
295                 (root)->ppm_suspend_time=0; \
296             } \
297         } \
298         else \
299         { \
300             (root)->ppm_suspend_time=0; \
301             if( (root)->ppm_disable_cnt > 0 ) \
302             (root)->ppm_disable_cnt--; \
303         } \
304     } \
305 }
306 
307 #define PPM_REENABLE_TREE(root,p) \
308     if( (root)->ppm_suspend_time && snort_conf->ppm_cfg.max_suspend_ticks ) \
309 { \
310     PPM_TICKS now = PPM_RULE_TIME(p); \
311     PPM_TICKS then = (root)->ppm_suspend_time + snort_conf->ppm_cfg.max_suspend_ticks; \
312     if( now > then ) \
313     { \
314         (root)->ppm_suspend_time=0; \
315         (root)->tree_state=RULE_STATE_ENABLED; \
316         ppm_clear_rule_event(&snort_conf->ppm_cfg, root); \
317         PPM_DBG_CSV("enabled", (root), now); \
318     } \
319     else \
320     { \
321         PPM_DBG_CSV("pending", (root), then-now); \
322     } \
323 }
324 
325 void ppm_init(ppm_cfg_t *);
326 #ifdef DEBUG
327 void ppm_set_debug_rules(ppm_cfg_t *, int);
328 void ppm_set_debug_pkts(ppm_cfg_t *, int);
329 #endif
330 
331 void ppm_set_pkt_action(ppm_cfg_t *, int);
332 void ppm_set_pkt_log(ppm_cfg_t *, int);
333 
334 void ppm_set_rule_action(ppm_cfg_t *, int);
335 void ppm_set_rule_threshold(ppm_cfg_t *, unsigned int);
336 void ppm_set_rule_log(ppm_cfg_t *, int);
337 
338 void ppm_set_max_pkt_time(ppm_cfg_t *, PPM_USECS);
339 void ppm_set_max_rule_time(ppm_cfg_t *, PPM_USECS);
340 void ppm_set_max_suspend_time(ppm_cfg_t *, PPM_SECS);
341 
342 void   ppm_print_cfg(ppm_cfg_t *);
343 void   ppm_print_summary(ppm_cfg_t *);
344 double ppm_ticks_to_usecs( PPM_TICKS );
345 
346 void ppm_pkt_log(ppm_cfg_t*, Packet*);
347 void ppm_set_rule_event (ppm_cfg_t *, detection_option_tree_root_t *);
348 void ppm_clear_rule_event (ppm_cfg_t *, detection_option_tree_root_t *);
349 void ppm_rule_log(ppm_cfg_t *, uint64_t, Packet *);
350 
351 void ppm_init_rules(void);
352 void ppm_set_rule(detection_option_tree_root_t *, PPM_TICKS);
353 
354 #define PPM_INIT()            ppm_init()
355 #define PPM_PRINT_CFG(x)      ppm_print_cfg(x)
356 #define PPM_PRINT_SUMMARY(x)  ppm_print_summary(x)
357 
358 #else /* !PPM_MGR */
359 
360 #define PPM_GET_TIME()
361 #define PPM_SET_TIME()
362 
363 
364 #endif /* PPM_MGR */
365 
366 #endif /* __PACKET_PROCESSING_MONITOR_H__ */
367 
368