1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <cassert>
25
26 #include "port_object.h"
27
28 #include "log/messages.h"
29 #include "parser/parser.h"
30 #include "utils/util.h"
31 #include "utils/util_cstring.h"
32
33 #include "port_group.h"
34 #include "port_item.h"
35 #include "port_utils.h"
36
37 using namespace snort;
38
39 //-------------------------------------------------------------------------
40 // PortObject - public
41 //-------------------------------------------------------------------------
42
PortObjectNew()43 PortObject* PortObjectNew()
44 {
45 PortObject* po = (PortObject*)snort_calloc(sizeof(PortObject));
46 po->item_list =(SF_LIST*)sflist_new();
47 po->rule_list =(SF_LIST*)sflist_new();
48 return po;
49 }
50
PortObjectFree(void * pv)51 void PortObjectFree(void* pv)
52 {
53 assert(pv);
54 PortObject* po = (PortObject*)pv;
55
56 if ( po->name )
57 snort_free(po->name);
58
59 if ( po->item_list)
60 sflist_free_all(po->item_list, snort_free);
61
62 if ( po->rule_list)
63 sflist_free_all(po->rule_list, snort_free);
64
65 if (po->group )
66 delete po->group;
67
68 snort_free(po);
69 }
70
PortObjectFinalize(PortObject * po)71 void PortObjectFinalize(PortObject* po)
72 {
73 sflist_free_all(po->item_list, snort_free);
74 sflist_free_all(po->rule_list, snort_free);
75
76 po->item_list = nullptr;
77 po->rule_list = nullptr;
78 }
79
80 /*
81 * Set the name of the Port Object
82 */
PortObjectSetName(PortObject * po,const char * name)83 int PortObjectSetName(PortObject* po, const char* name)
84 {
85 if ( !po )
86 return -1;
87
88 if ( !name )
89 return -1;
90
91 /* free the old name */
92 if (po->name)
93 snort_free(po->name);
94
95 /* alloc a new name */
96 po->name = snort_strdup(name);
97 return 0;
98 }
99
100 /*
101 * Add a PortObjectItem to a PortObject
102 */
PortObjectAddItem(PortObject * po,PortObjectItem * poi,int * errflag)103 int PortObjectAddItem(PortObject* po, PortObjectItem* poi, int* errflag)
104 {
105 PortObjectItem* p;
106 SF_LNODE* pos = nullptr;
107
108 if (!po || !poi)
109 return 0;
110
111 if (errflag)
112 *errflag = 0;
113
114 /* Make sure this is not a duplicate */
115 for (p = (PortObjectItem*)sflist_first(po->item_list,&pos);
116 p != nullptr;
117 p = (PortObjectItem*)sflist_next(&pos))
118 {
119 if ((p->lport == poi->lport) && (p->hport == poi->hport))
120 ParseWarning(WARN_RULES, "duplicate ports in list");
121 }
122
123 sflist_add_tail(po->item_list, poi);
124 return 0;
125 }
126
127 /*
128 * Add a PortObjectItem to a PortObject
129 */
PortObjectAddPortObject(PortObject * podst,PortObject * posrc,int * errflag)130 int PortObjectAddPortObject(PortObject* podst, PortObject* posrc, int* errflag)
131 {
132 PortObjectItem* po;
133 SF_LNODE* pos = nullptr;
134 int ret = 0;
135
136 if (errflag)
137 *errflag = 0;
138
139 for (po=(PortObjectItem*)sflist_first(posrc->item_list, &pos);
140 po != nullptr;
141 po=(PortObjectItem*)sflist_next(&pos) )
142 {
143 PortObjectItem* poi = PortObjectItemDup(po);
144 if ((ret = PortObjectAddItem(podst, poi, errflag)) != 0)
145 {
146 PortObjectItemFree(poi);
147 return ret;
148 }
149 }
150
151 return ret;
152 }
153
PortObjectAddPort(PortObject * po,int port)154 int PortObjectAddPort(PortObject* po, int port)
155 {
156 return PortObjectAddRange(po, port, port);
157 }
158
PortObjectAddRange(PortObject * po,int lport,int hport)159 int PortObjectAddRange(PortObject* po, int lport, int hport)
160 {
161 PortObjectItem* poi = PortObjectItemNew();
162 poi->lport = (unsigned short)lport;
163 poi->hport = (unsigned short)hport;
164
165 sflist_add_tail(po->item_list, poi);
166 return 0;
167 }
168
PortObjectAddRule(PortObject * po,int rule)169 int PortObjectAddRule(PortObject* po, int rule)
170 {
171 int* pruleid;
172
173 //LogMessage("Adding Rule %d to Port Object '%s'\n",rule,po->name);
174 if ( !po )
175 return -1;
176
177 if ( !po->rule_list )
178 return -1;
179
180 /* Add rule index to rule list */
181 pruleid = (int*)snort_calloc(sizeof(int));
182 *pruleid = rule;
183
184 sflist_add_tail(po->rule_list, pruleid);
185 return 0;
186 }
187
PortObjectAddPortAny(PortObject * po)188 int PortObjectAddPortAny(PortObject* po)
189 {
190 if (!po->name)
191 po->name = snort_strdup("any");
192
193 return PortObjectAddRange(po, 0, SFPO_MAX_PORTS-1);
194 }
195
196 /*
197 * Dup the PortObjects Item List, RuleList, and Name
198 */
PortObjectDup(PortObject * po)199 PortObject* PortObjectDup(PortObject* po)
200 {
201 SF_LNODE* lpos = nullptr;
202 PortObject* ponew = PortObjectNew();
203
204 /* Dup the Name */
205 if ( po->name )
206 ponew->name = snort_strdup(po->name);
207 else
208 ponew->name = snort_strdup("dup");
209
210 /* Dup the Item List */
211 if ( po->item_list )
212 {
213 for (PortObjectItem* poi = (PortObjectItem*)sflist_first(po->item_list, &lpos);
214 poi != nullptr;
215 poi = (PortObjectItem*)sflist_next(&lpos) )
216 {
217 PortObjectItem* poinew = PortObjectItemDup(poi);
218 PortObjectAddItem(ponew, poinew, nullptr);
219 }
220 }
221
222 /* Dup the input rule list */
223 if ( po->rule_list )
224 {
225 for (int* prid = (int*)sflist_first(po->rule_list, &lpos);
226 prid != nullptr;
227 prid = (int*)sflist_next(&lpos) )
228 {
229 int* prule = (int*)snort_calloc(sizeof(int));
230 *prule = *prid;
231 sflist_add_tail(ponew->rule_list, prule);
232 }
233 }
234
235 return ponew;
236 }
237
238 /*
239 * Dup the PortObjects Item List, and Name
240 */
PortObjectDupPorts(PortObject * po)241 PortObject* PortObjectDupPorts(PortObject* po)
242 {
243 SF_LNODE* lpos = nullptr;
244 PortObject* ponew = PortObjectNew();
245
246 /* Dup the Name */
247 if ( po->name )
248 ponew->name = snort_strdup(po->name);
249 else
250 ponew->name = snort_strdup("dup");
251
252 /* Dup the Item List */
253 if ( po->item_list )
254 {
255 for (PortObjectItem* poi = (PortObjectItem*)sflist_first(po->item_list, &lpos);
256 poi != nullptr;
257 poi = (PortObjectItem*)sflist_next(&lpos))
258 {
259 PortObjectItem* poinew = PortObjectItemDup(poi);
260 PortObjectAddItem(ponew, poinew, nullptr);
261 }
262 }
263 return ponew;
264 }
265
266 /*
267 * Normalize a port object
268 *
269 * The reduces multiple references to a given port to a single unique reference
270 * This function should be used on each PortObject, once it's completed. After
271 * the normalized PortObject is created, the input PortObject may be deleted.
272 */
PortObjectNormalize(PortObject * po)273 int PortObjectNormalize(PortObject* po)
274 {
275 if ( PortObjectHasAny (po) )
276 return 0; /* ANY =64K */
277
278 PortBitSet parray;
279 int nports = PortObjectBits(parray, po);
280
281 sflist_free_all(po->item_list, snort_free);
282 po->item_list = PortObjectItemListFromBits(parray, SFPO_MAX_PORTS);
283
284 return nports;
285 }
286
287 /*
288 PortObjects should be normalized, prior to testing
289 */
PortObjectEqual(PortObject * a,PortObject * b)290 bool PortObjectEqual(PortObject* a, PortObject* b)
291 {
292 PortObjectItem* pa;
293 PortObjectItem* pb;
294 SF_LNODE* posa;
295 SF_LNODE* posb;
296
297 if ( a->item_list->count != b->item_list->count )
298 return false;
299
300 pa = (PortObjectItem*)sflist_first(a->item_list,&posa);
301 pb = (PortObjectItem*)sflist_first(b->item_list,&posb);
302
303 while ( pa && pb )
304 {
305 if ( !PortObjectItemsEqual(pa, pb) )
306 return false;
307
308 pa = (PortObjectItem*)sflist_next(&posa);
309 pb = (PortObjectItem*)sflist_next(&posb);
310 }
311
312 if ( pa || pb ) /* both are not done - cannot match */
313 return false;
314
315 return true; /* match */
316 }
317
318 /*
319 * Calcs number of ports in this object,
320 * object do not have to be normalized,
321 * but if the same ports are referenced
322 * twice, the count will be off.
323 *
324 * returns:
325 * any = -1
326 * 0 = none/empty
327 * >0 = number of ports
328 */
PortObjectPortCount(PortObject * po)329 int PortObjectPortCount(PortObject* po)
330 {
331 SF_LNODE* cursor;
332 int cnt=0;
333
334 if ( !po )
335 return 0;
336
337 for (PortObjectItem* poi=(PortObjectItem*)sflist_first(po->item_list, &cursor);
338 poi != nullptr;
339 poi=(PortObjectItem*)sflist_next(&cursor) )
340 {
341 if ( poi->any() )
342 return -1;
343
344 int nports = poi->hport - poi->lport + 1;
345
346 if ( poi->negate )
347 cnt -= nports;
348 else
349 cnt += nports;
350 }
351
352 if ( cnt < 0 )
353 {
354 /* we have a pure not port or port range
355 *
356 * !80 = -1, add 64K (65535 -1 = 65534)
357 * !80:81 = -2, (65535 - 2 = 65533)
358 *
359 * [:1023,!80] = 1024 - 1 = 1023 ports
360 *
361 */
362 cnt += SFPO_MAX_PORTS; /* add back in the acceptable ports */
363 }
364
365 return cnt;
366 }
367
368 /*
369 * This does NOT return true if the object is an ANY port
370 */
PortObjectHasPort(PortObject * po,int port)371 int PortObjectHasPort(PortObject* po, int port)
372 {
373 PortObjectItem* poi;
374 SF_LNODE* cursor;
375
376 if ( !po )
377 return 0;
378
379 for (poi=(PortObjectItem*)sflist_first(po->item_list, &cursor);
380 poi != nullptr;
381 poi=(PortObjectItem*)sflist_next(&cursor) )
382 {
383 if ( poi->any() )
384 return 0;
385
386 // FIXIT-L need to check range based on flag???
387 if ( (uint16_t)port >= poi->lport &&
388 (uint16_t)port <= poi->hport )
389 return 1;
390
391 if ( poi->negate )
392 return 1;
393 }
394 return 0;
395 }
396
PortObjectToggle(PortObject * po)397 void PortObjectToggle(PortObject* po)
398 {
399 PortObjectItem* poi;
400 SF_LNODE* pos;
401
402 if (!po)
403 return;
404
405 for (poi=(PortObjectItem*)sflist_first(po->item_list,&pos);
406 poi != nullptr;
407 poi=(PortObjectItem*)sflist_next(&pos) )
408 {
409 poi->negate = !poi->negate;
410 }
411 }
412
PortObjectIsPureNot(PortObject * po)413 int PortObjectIsPureNot(PortObject* po)
414 {
415 PortObjectItem* poi;
416 SF_LNODE* cursor;
417 int cnt=0;
418
419 if ( !po )
420 return 0;
421
422 for (poi=(PortObjectItem*)sflist_first(po->item_list, &cursor);
423 poi != nullptr;
424 poi=(PortObjectItem*)sflist_next(&cursor) )
425 {
426 cnt++;
427 if ( !poi->negate )
428 return 0;
429 }
430
431 if ( cnt == 0 )
432 return 0;
433
434 return 1;
435 }
436
PortObjectHasAny(PortObject * po)437 int PortObjectHasAny(PortObject* po)
438 {
439 PortObjectItem* poi;
440 SF_LNODE* cursor;
441
442 if ( !po )
443 return 0;
444
445 for (poi=(PortObjectItem*)sflist_first(po->item_list, &cursor);
446 poi != nullptr;
447 poi=(PortObjectItem*)sflist_next(&cursor) )
448 {
449 if ( poi->any() )
450 return 1;
451 }
452 return 0;
453 }
454
455 /*
456 * Removes Ports in B from A ... A = A - B
457 */
PortObjectRemovePorts(PortObject * a,PortObject * b)458 int PortObjectRemovePorts(PortObject* a, PortObject* b)
459 {
460 PortBitSet pA, pB;
461
462 PortObjectBits(pA, a);
463 PortObjectBits(pB, b);
464
465 pA &= ~pB;
466
467 /* Release the old port list */
468 sflist_free_all(a->item_list, snort_free);
469
470 /* Replace the old PortObject list */
471 a->item_list = PortObjectItemListFromBits(pA, SFPO_MAX_PORTS);
472
473 return 0;
474 }
475
476 /*
477 Dup and Append PortObjectItems from pob to poa
478 */
PortObjectAppend(PortObject * poa,PortObject * pob)479 PortObject* PortObjectAppend(PortObject* poa, PortObject* pob)
480 {
481 SF_LNODE* cursor;
482
483 for (PortObjectItem* poib = (PortObjectItem*)sflist_first(pob->item_list, &cursor);
484 poib!= nullptr;
485 poib = (PortObjectItem*)sflist_next(&cursor) )
486 {
487 PortObjectItem* poia = PortObjectItemNew();
488
489 if (!poia)
490 return nullptr;
491
492 memcpy(poia,poib,sizeof(PortObjectItem));
493
494 sflist_add_tail(poa->item_list,poia);
495 }
496 return poa;
497 }
498
PortObjectPrint(PortObject * po)499 void PortObjectPrint(PortObject* po)
500 {
501 PortObjectPrintEx(po, rule_index_map_print_index);
502 }
503
PortObjectPrintPortsRaw(PortObject * po)504 void PortObjectPrintPortsRaw(PortObject* po)
505 {
506 PortObjectItem* poi = nullptr;
507 SF_LNODE* pos = nullptr;
508 char* buf;
509 int bufsize;
510
511 /* Need to buffer the string so we only do one LogMessage,
512 * due to syslog output. The largest string needed to represent
513 * each portobject is the length required to represent:
514 * " unknown port type @ 0x<8 max bytes>" (See PortObjectItemPrint), or:
515 * 30 bytes. For the entire list, need room for spaces and brackets and
516 * potential negations. Or:
517 * list_size * (30 + 1space_for_each_element, +
518 * 1potential_negation) + surrounding_whitespace + brackets + null */
519
520 bufsize = po->item_list->count * (30 + 1 + 1) + 5;
521 buf = (char*)snort_calloc(bufsize);
522 SnortSnprintfAppend(buf, bufsize, " [");
523
524 for (poi=(PortObjectItem*)sflist_first(po->item_list, &pos);
525 poi != nullptr;
526 poi=(PortObjectItem*)sflist_next(&pos) )
527 {
528 PortObjectItemPrint(poi, buf, bufsize);
529 }
530
531 SnortSnprintfAppend(buf, bufsize, " ]");
532
533 LogMessage("%s", buf);
534
535 snort_free(buf);
536 }
537
538 /*
539 Print Port Object - Prints input ports and rules (uncompiled)
540 ports
541 rules (input by user)
542 */
PortObjectPrintEx(PortObject * po,po_print_f print_index_map)543 void PortObjectPrintEx(PortObject* po, po_print_f print_index_map)
544 {
545 PortObjectItem* poi = nullptr;
546 SF_LNODE* pos = nullptr;
547 int k=0;
548 int* rlist = nullptr;
549 unsigned i;
550
551 /* static for printing so we don't put so many bytes on the stack */
552 static char print_buf[MAX_PORTS]; // FIXIT-L delete this; replace with local stringstream
553
554 int bufsize = sizeof(print_buf);
555 print_buf[0] = '\0';
556
557 if ( !po )
558 return;
559
560 if ( !po->rule_list )
561 return;
562
563 if ( !po->rule_list->count )
564 return;
565
566 SnortSnprintfAppend(print_buf, bufsize, " PortObject ");
567
568 if ( po->name )
569 SnortSnprintfAppend(print_buf, bufsize, "%s ", po->name);
570
571 SnortSnprintfAppend(print_buf, bufsize,
572 " Id:%d Ports:%u Rules:%u\n {\n",
573 po->id, po->item_list->count, po->rule_list->count);
574
575 SnortSnprintfAppend(print_buf, bufsize, " Ports [\n ");
576
577 if ( PortObjectHasAny(po) )
578 {
579 SnortSnprintfAppend(print_buf, bufsize, "any");
580 }
581 else
582 {
583 for (poi = (PortObjectItem*)sflist_first(po->item_list,&pos);
584 poi != nullptr;
585 poi = (PortObjectItem*)sflist_next(&pos) )
586 {
587 PortObjectItemPrint(poi, print_buf, bufsize);
588 }
589 }
590 SnortSnprintfAppend(print_buf, bufsize, " ]\n");
591
592 rlist = RuleListToSortedArray(po->rule_list);
593 if (!rlist )
594 {
595 return;
596 }
597
598 SnortSnprintfAppend(print_buf, bufsize, " Rules [ \n ");
599 for (i = 0; i < po->rule_list->count; i++)
600 {
601 if ( print_index_map )
602 print_index_map(rlist[i], print_buf, bufsize);
603 else
604 SnortSnprintfAppend(print_buf, bufsize, " %d",rlist[i]);
605
606 k++;
607 if ( k == 25 )
608 {
609 k=0;
610 SnortSnprintfAppend(print_buf, bufsize, " \n ");
611 }
612 }
613 SnortSnprintfAppend(print_buf, bufsize, " ]\n }\n");
614
615 LogMessage("%s", print_buf);
616 snort_free(rlist);
617 }
618
619