00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2013-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023
00024 #include "parse_rule.h"
00025
00026 #include "detection/detect.h"
00027 #include "detection/fp_config.h"
00028 #include "detection/fp_utils.h"
00029 #include "detection/rtn_checks.h"
00030 #include "detection/treenodes.h"
00031 #include "framework/decode_data.h"
00032 #include "hash/sfxhash.h"
00033 #include "log/messages.h"
00034 #include "main/snort_config.h"
00035 #include "main/snort_debug.h"
00036 #include "main/thread_config.h"
00037 #include "managers/ips_manager.h"
00038 #include "managers/module_manager.h"
00039 #include "managers/so_manager.h"
00040 #include "ports/rule_port_tables.h"
00041 #include "sfip/sf_ipvar.h"
00042 #include "sfip/sf_vartable.h"
00043 #include "target_based/snort_protocols.h"
00044 #include "utils/util.h"
00045 #include "ips_options/extract.h"
00046
00047 #include "parser.h"
00048 #include "parse_conf.h"
00049 #include "parse_ports.h"
00050
00051 #include "parser.h"
00052 #include "cmd_line.h"
00053 #include "config_file.h"
00054 #include "parse_conf.h"
00055 #include "parse_ports.h"
00056
00057 #define SRC 0
00058 #define DST 1
00059
00060 /* rule counts for port lists */
00061 struct rule_count_t
00062 {
00063 int src;
00064 int dst;
00065 int any;
00066 int both;
00067 };
00068
00069 static int rule_count = 0;
00070 static int detect_rule_count = 0;
00071 static int builtin_rule_count = 0;
00072 static int so_rule_count = 0;
00073 static int head_count = 0; /* number of header blocks (chain heads?) */
00074 static int otn_count = 0; /* number of chains */
00075 static int rule_proto = 0;
00076
00077 static rule_count_t tcpCnt;
00078 static rule_count_t udpCnt;
00079 static rule_count_t icmpCnt;
00080 static rule_count_t ipCnt;
00081 static rule_count_t svcCnt; // dummy for now
00082
00083 static bool s_ignore = false; // for skipping drop rules when not inline, etc.
00084
00085 /*
00086 * Finish adding the rule to the port tables
00087 *
00088 * 1) find the table this rule should belong to (src/dst/any-any tcp,udp,icmp,ip or nocontent)
00089 * 2) find an index for the gid:sid pair
00090 * 3) add all no content rules to a single no content port object, the ports are irrelevant so
00091 * make it a any-any port object.
00092 * 4) if it's an any-any rule with content, add to an any-any port object
00093 * 5) find if we have a port object with these ports defined, if so get it, otherwise create it.
00094 * a)do this for src and dst port
00095 * b)add the rule index/id to the portobject(s)
00096 * c)if the rule is bidir add the rule and port-object to both src and dst tables
00097 */
00098 static int FinishPortListRule(
00099 RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn,
00100 int proto, FastPatternConfig* fp)
00101 {
00102 int large_port_group = 0;
00103 int src_cnt = 0;
00104 int dst_cnt = 0;
00105 PortTable* dstTable;
00106 PortTable* srcTable;
00107 PortObject* aaObject;
00108 rule_count_t* prc;
00109 uint32_t orig_flags = rtn->flags;
00110
00111 assert(otn->proto == proto);
00112
00113 /* Select the Target PortTable for this rule, based on protocol, src/dst
00114 * dir, and if there is rule content */
00115 switch ( proto )
00116 {
00117 case SNORT_PROTO_IP:
00118 dstTable = port_tables->ip.dst;
00119 srcTable = port_tables->ip.src;
00120 aaObject = port_tables->ip.any;
00121 prc = &ipCnt;
00122 break;
00123
00124 case SNORT_PROTO_ICMP:
00125 dstTable = port_tables->icmp.dst;
00126 srcTable = port_tables->icmp.src;
00127 aaObject = port_tables->icmp.any;
00128 prc = &icmpCnt;
00129 break;
00130
00131 case SNORT_PROTO_TCP:
00132 dstTable = port_tables->tcp.dst;
00133 srcTable = port_tables->tcp.src;
00134 aaObject = port_tables->tcp.any;
00135 prc = &tcpCnt;
00136 break;
00137
00138 case SNORT_PROTO_UDP:
00139 dstTable = port_tables->udp.dst;
00140 srcTable = port_tables->udp.src;
00141 aaObject = port_tables->udp.any;
00142 prc = &udpCnt;
00143 break;
00144
00145 default:
00146 rtn->flags |= ANY_SRC_PORT|ANY_DST_PORT;
00147 dstTable = srcTable = nullptr;
00148 aaObject = port_tables->svc_any;
00149 prc = &svcCnt;
00150 }
00151
00152 /* Count rules with both src and dst specific ports */
00153 if (!(rtn->flags & ANY_DST_PORT) && !(rtn->flags & ANY_SRC_PORT))
00154 {
00155 DebugFormat(DEBUG_PORTLISTS,
00156 "***\n***Info: src & dst ports are both specific"
00157 " >> gid=%u sid=%u\n***\n",
00158 otn->sigInfo.gid, otn->sigInfo.sid);
00159
00160 prc->both++;
00161 }
00162
00163 /* If not an any-any rule test for port bleedover, if we are using a
00164 * single rule group, don't bother */
00165 if (!fp->get_single_rule_group() &&
00166 (rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) != (ANY_DST_PORT|ANY_SRC_PORT))
00167 {
00168 if (!(rtn->flags & ANY_SRC_PORT))
00169 {
00170 src_cnt = PortObjectPortCount(rtn->src_portobject);
00171 if (src_cnt >= fp->get_bleed_over_port_limit())
00172 large_port_group = 1;
00173 }
00174
00175 if (!(rtn->flags & ANY_DST_PORT))
00176 {
00177 dst_cnt = PortObjectPortCount(rtn->dst_portobject);
00178 if (dst_cnt >= fp->get_bleed_over_port_limit())
00179 large_port_group = 1;
00180 }
00181
00182 if (large_port_group && fp->get_bleed_over_warnings())
00183 {
00184 LogMessage("***Bleedover Port Limit(%d) Exceeded for rule %u:%u "
00185 "(%d)ports: ", fp->get_bleed_over_port_limit(),
00186 otn->sigInfo.gid, otn->sigInfo.sid,
00187 (src_cnt > dst_cnt) ? src_cnt : dst_cnt);
00188
00189 /* If logging to syslog, this will be all multiline */
00190 fflush(stdout); fflush(stderr);
00191 PortObjectPrintPortsRaw(rtn->src_portobject);
00192 LogMessage(" -> ");
00193 PortObjectPrintPortsRaw(rtn->dst_portobject);
00194 LogMessage(" adding to any-any group\n");
00195 fflush(stdout); fflush(stderr);
00196 }
00197 }
00198
00199 /* If an any-any rule add rule index to any-any port object
00200 * both content and no-content type rules go here if they are
00201 * any-any port rules...
00202 * If we have an any-any rule or a large port group or
00203 * were using a single rule group we make it an any-any rule. */
00204 if (((rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) == (ANY_DST_PORT|ANY_SRC_PORT)) ||
00205 large_port_group || fp->get_single_rule_group())
00206 {
00207 if (proto == SNORT_PROTO_IP)
00208 {
00209 /* Add the IP rules to the higher level app protocol groups, if they apply
00210 * to those protocols. All IP rules should have any-any port descriptors
00211 * and fall into this test. IP rules that are not tcp/udp/icmp go only into the
00212 * IP table */
00213 DebugFormat(DEBUG_PORTLISTS,
00214 "Finishing IP any-any rule %u:%u\n",
00215 otn->sigInfo.gid, otn->sigInfo.sid);
00216
00217 switch ( otn->proto )
00218 {
00219 case SNORT_PROTO_IP: /* Add to all ip proto any port tables */
00220 PortObjectAddRule(port_tables->icmp.any, otn->ruleIndex);
00221 icmpCnt.any++;
00222
00223 PortObjectAddRule(port_tables->tcp.any, otn->ruleIndex);
00224 tcpCnt.any++;
00225
00226 PortObjectAddRule(port_tables->udp.any, otn->ruleIndex);
00227 udpCnt.any++;
00228 break;
00229
00230 case SNORT_PROTO_ICMP:
00231 PortObjectAddRule(port_tables->icmp.any, otn->ruleIndex);
00232 icmpCnt.any++;
00233 break;
00234
00235 case SNORT_PROTO_TCP:
00236 PortObjectAddRule(port_tables->tcp.any, otn->ruleIndex);
00237 tcpCnt.any++;
00238 break;
00239
00240 case SNORT_PROTO_UDP:
00241 PortObjectAddRule(port_tables->udp.any, otn->ruleIndex);
00242 udpCnt.any++;
00243 break;
00244
00245 default:
00246 break;
00247 }
00248 }
00249 /* For all protocols-add to the any any group */
00250 PortObjectAddRule(aaObject, otn->ruleIndex);
00251 prc->any++;
00252 rtn->flags = orig_flags;
00253 return 0; /* done */
00254 }
00255
00256 /* add rule index to dst table if we have a specific dst port or port list */
00257 if (!(rtn->flags & ANY_DST_PORT))
00258 {
00259 prc->dst++;
00260 DebugMessage(DEBUG_PORTLISTS, "Finishing rule: dst port rule\n");
00261
00262 /* find the proper port object */
00263 PortObject* pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
00264 if ( !pox )
00265 {
00266 /* Create a permanent port object */
00267 pox = PortObjectDupPorts(rtn->dst_portobject);
00268 if ( !pox )
00269 {
00270 ParseError("could not dup a port object - out of memory.");
00271 return -1;
00272 }
00273
00274 /* Add the port object to the table, and add the rule to the port object */
00275 PortTableAddObject(dstTable, pox);
00276 }
00277
00278 PortObjectAddRule(pox, otn->ruleIndex);
00279
00280 /* if bidir, add this rule and port group to the src table */
00281 if (rtn->flags & BIDIRECTIONAL)
00282 {
00283 pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
00284 if ( !pox )
00285 {
00286 pox = PortObjectDupPorts(rtn->dst_portobject);
00287 if ( !pox )
00288 {
00289 ParseError("could not dup a bidir-port object - out of memory.");
00290 return -1;
00291 }
00292
00293 PortTableAddObject(srcTable, pox);
00294 }
00295
00296 PortObjectAddRule(pox, otn->ruleIndex);
00297 }
00298 }
00299
00300 /* add rule index to src table if we have a specific src port or port list */
00301 if (!(rtn->flags & ANY_SRC_PORT))
00302 {
00303 prc->src++;
00304 PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
00305
00306 if ( !pox )
00307 {
00308 pox = PortObjectDupPorts(rtn->src_portobject);
00309 if ( !pox )
00310 {
00311 ParseError("could not dup a port object - out of memory.");
00312 return -1;
00313 }
00314 PortTableAddObject(srcTable, pox);
00315 }
00316
00317 PortObjectAddRule(pox, otn->ruleIndex);
00318
00319 /* if bidir, add this rule and port group to the dst table */
00320 if (rtn->flags & BIDIRECTIONAL)
00321 {
00322 pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
00323 if ( !pox )
00324 {
00325 pox = PortObjectDupPorts(rtn->src_portobject);
00326 if ( !pox )
00327 {
00328 ParseError("could not dup a bidir-port object - out of memory.");
00329 return -1;
00330 }
00331
00332 PortTableAddObject(dstTable, pox);
00333 }
00334 PortObjectAddRule(pox, otn->ruleIndex);
00335 }
00336 }
00337 return 0;
00338 }
00339
00340 static int ValidateIPList(sfip_var_t* addrset, const char* token)
00341 {
00342 if (!addrset || !(addrset->head||addrset->neg_head))
00343 {
00344 ParseError("empty IP used either as source IP or as "
00345 "destination IP in a rule. IP list: %s.", token);
00346 return -1;
00347 }
00348 return 0;
00349 }
00350
00351 static int ProcessIP(
00352 SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode, int)
00353 {
00354 vartable_t* ip_vartable = get_ips_policy()->ip_vartable;
00355
00356 assert(rtn);
00357 /* If a rule has a variable in it, we want to copy that variable's
00358 * contents to the IP variable (IP list) stored with the rtn.
00359 * This code tries to look up the variable, and if found, will copy it
00360 * to the rtn->{sip,dip} */
00361 if (mode == SRC)
00362 {
00363 int ret;
00364
00365 if ( !rtn->sip )
00366 {
00367 sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr);
00368 if ( tmp )
00369 {
00370 rtn->sip = sfvar_create_alias(tmp, tmp->name);
00371 ret = rtn->sip ? SFIP_SUCCESS : SFIP_FAILURE;
00372 }
00373 else
00374 {
00375 rtn->sip = (sfip_var_t*)snort_calloc(sizeof(sfip_var_t));
00376 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
00377 }
00378 }
00379 else
00380 {
00381 ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
00382 }
00383
00384 /* The function sfvt_add_to_var adds 'addr' to the variable 'rtn->sip' */
00385 if (ret != SFIP_SUCCESS)
00386 {
00387 if (ret == SFIP_LOOKUP_FAILURE)
00388 {
00389 ParseError("Undefined variable in the string: %s.", addr);
00390 return -1;
00391 }
00392 else if (ret == SFIP_CONFLICT)
00393 {
00394 ParseError("Negated IP ranges that are more general than "
00395 "non-negated ranges are not allowed. Consider "
00396 "inverting the logic: %s.", addr);
00397 return -1;
00398 }
00399 else if (ret == SFIP_NOT_ANY)
00400 {
00401 ParseError("!any is not allowed: %s.", addr);
00402 return -1;
00403 }
00404 else
00405 {
00406 ParseError("Unable to process the IP address: %s.", addr);
00407 return -1;
00408 }
00409 }
00410
00411 if (rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
00412 {
00413 rtn->flags |= ANY_SRC_IP;
00414 }
00415 }
00416 /* mode == DST */
00417 else
00418 {
00419 int ret;
00420
00421 if ( !rtn->dip )
00422 {
00423 sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr);
00424 if ( tmp )
00425 {
00426 rtn->dip = sfvar_create_alias(tmp, tmp->name);
00427 ret = rtn->dip ? SFIP_SUCCESS : SFIP_FAILURE;
00428 }
00429 else
00430 {
00431 rtn->dip = (sfip_var_t*)snort_calloc(sizeof(sfip_var_t));
00432 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
00433 }
00434 }
00435 else
00436 {
00437 ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
00438 }
00439
00440 if (ret != SFIP_SUCCESS)
00441 {
00442 if (ret == SFIP_LOOKUP_FAILURE)
00443 {
00444 ParseError("undefined variable in the string: %s.", addr);
00445 return -1;
00446 }
00447 else if (ret == SFIP_CONFLICT)
00448 {
00449 ParseError("negated IP ranges that are more general than "
00450 "non-negated ranges are not allowed. Consider "
00451 "inverting the logic: %s.", addr);
00452 return -1;
00453 }
00454 else if (ret == SFIP_NOT_ANY)
00455 {
00456 ParseError("!any is not allowed: %s.", addr);
00457 return -1;
00458 }
00459 else
00460 {
00461 ParseError("unable to process the IP address: %s.", addr);
00462 return -1;
00463 }
00464 }
00465
00466 if (rtn->dip->head && rtn->dip->head->flags & SFIP_ANY)
00467 {
00468 rtn->flags |= ANY_DST_IP;
00469 }
00470 }
00471
00472 /* Make sure the IP lists provided by the user are valid */
00473 if (mode == SRC)
00474 ValidateIPList(rtn->sip, addr);
00475 else
00476 ValidateIPList(rtn->dip, addr);
00477
00478 return 0;
00479 }
00480
00481 /*
00482 * Parse a port string as a port var, and create or find a port object for it,
00483 * and add it to the port var table. These are used by the rtn's
00484 * as src and dst port lists for final rtn/otn processing.
00485 *
00486 * These should not be confused with the port objects used to merge ports and rules
00487 * to build port group objects. Those are generated after the otn processing.
00488 */
00489 static PortObject* ParsePortListTcpUdpPort(
00490 PortVarTable* pvt, PortTable* noname, const char* port_str)
00491 {
00492 PortObject* portobject;
00493 POParser poparser;
00494
00495 if ( !pvt or !noname or !port_str )
00496 return nullptr;
00497
00498 /* 1st - check if we have an any port */
00499 if ( strcasecmp(port_str,"any")== 0 )
00500 {
00501 portobject = PortVarTableFind(pvt, "any");
00502 if ( !portobject )
00503 ParseAbort("PortVarTable missing an 'any' variable.");
00504
00505 return portobject;
00506 }
00507 /* 2nd - check if we have a PortVar */
00508 else if ( port_str[0]=='$' )
00509 {
00510 /*||isalpha(port_str[0])*/ /*TODO: interferes with protocol names for ports*/
00511 const char* name = port_str + 1;
00512
00513 DebugFormat(DEBUG_PORTLISTS,"PortVarTableFind: finding '%s'\n", port_str);
00514
00515 /* look it up in the port var table */
00516 portobject = PortVarTableFind(pvt, name);
00517 if ( !portobject )
00518 ParseAbort("***PortVar Lookup failed on '%s'.", port_str);
00519
00520 DebugFormat(DEBUG_PORTLISTS,"PortVarTableFind: '%s' found!\n", port_str);
00521 }
00522 /* 3rd - and finally process a raw port list */
00523 else
00524 {
00525 /* port list = [p,p,p:p,p,...] or p or p:p , no embedded spaces due to tokenizer */
00526 PortObject* pox;
00527
00528 DebugFormat(DEBUG_PORTLISTS,
00529 "parser.c->PortObjectParseString: parsing '%s'\n",port_str);
00530
00531 portobject = PortObjectParseString(pvt, &poparser, nullptr, port_str, 0);
00532
00533 DebugFormat(DEBUG_PORTLISTS,
00534 "parser.c->PortObjectParseString: '%s' done.\n",port_str);
00535
00536 if ( !portobject )
00537 {
00538 const char* errstr = PortObjectParseError(&poparser);
00539 ParseAbort("***Rule--PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s",
00540 poparser.pos,errstr,port_str,poparser.pos,"^");
00541 }
00542
00543 /* check if we already have this port object in the un-named port var table ... */
00544 pox = PortTableFindInputPortObjectPorts(noname, portobject);
00545 if ( pox )
00546 {
00547 DebugFormat(DEBUG_PORTLISTS,
00548 "parser.c: already have '%s' as a PortObject - "
00549 "calling PortObjectFree(portobject)\n", port_str);
00550 PortObjectFree(portobject);
00551 portobject = pox;
00552 }
00553 else
00554 {
00555 DebugFormat(DEBUG_PORTLISTS,
00556 "parser.c: adding '%s' as a PortObject\n",port_str);
00557 /* Add to the un-named port var table */
00558 if (PortTableAddObject(noname, portobject))
00559 {
00560 ParseAbort("Unable to add raw port object to unnamed "
00561 "port var table, out of memory.");
00562 }
00563 }
00564 }
00565
00566 return portobject;
00567 }
00568
00569 /*
00570 * Process the rule, add it to the appropriate PortObject
00571 * and add the PortObject to the rtn.
00572 *
00573 * TCP/UDP rules use ports/portlists, icmp uses the icmp type field and ip uses the protocol
00574 * field as a dst port for the purposes of looking up a rule group as packets are being
00575 * processed.
00576 *
00577 * TCP/UDP- use src/dst ports
00578 * ICMP - use icmp type as dst port,src=-1
00579 * IP - use protocol as dst port,src=-1
00580 *
00581 * rtn - proto_node
00582 * port_str - port list string or port var name
00583 * proto - protocol
00584 * dst_flag - dst or src port flag, true = dst, false = src
00585 *
00586 */
00587 static int ParsePortList(
00588 RuleTreeNode* rtn, PortVarTable* pvt, PortTable* noname,
00589 const char* port_str, int dst_flag)
00590 {
00591 PortObject* portobject; /* src or dst */
00592
00593 /* Get the protocol specific port object */
00594 if ( rule_proto & (PROTO_BIT__TCP | PROTO_BIT__UDP) )
00595 {
00596 portobject = ParsePortListTcpUdpPort(pvt, noname, port_str);
00597 }
00598 else /* ICMP, IP - no real ports just Type and Protocol */
00599 {
00600 portobject = PortVarTableFind(pvt, "any");
00601 if ( !portobject )
00602 {
00603 ParseError("PortVarTable missing an 'any' variable.");
00604 return -1;
00605 }
00606 }
00607
00608 DebugFormat(DEBUG_PORTLISTS,"Rule-PortVar Parsed: %s \n",port_str);
00609
00610 /* !ports - port lists can be mixed 80:90,!82,
00611 * so the old NOT flag is deprecated for port lists
00612 */
00613
00614 /* set up any any flags */
00615 if ( PortObjectHasAny(portobject) )
00616 {
00617 if ( dst_flag )
00618 rtn->flags |= ANY_DST_PORT;
00619 else
00620 rtn->flags |= ANY_SRC_PORT;
00621 }
00622
00623 /* check for a pure not rule - fatal if we find one */
00624 if ( PortObjectIsPureNot(portobject) )
00625 {
00626 ParseError("Pure NOT ports are not allowed.");
00627 return -1;
00628 /*
00629 if( dst_flag )
00630 rtn->flags |= EXCEPT_DST_PORT;
00631 else
00632 rtn->flags |= EXCEPT_SRC_PORT;
00633 */
00634 }
00635
00636 /*
00637 * set to the port object for this rules src/dst port,
00638 * these are used during rtn/otn port verification of the rule.
00639 */
00640
00641 if (dst_flag)
00642 rtn->dst_portobject = portobject;
00643 else
00644 rtn->src_portobject = portobject;
00645
00646 return 0;
00647 }
00648
00649 bool same_headers(RuleTreeNode* rule, RuleTreeNode* rtn)
00650 {
00651 if ( !rule or !rtn )
00652 return false;
00653
00654 if (rule->type != rtn->type)
00655 return false;
00656
00657 if (rule->proto != rtn->proto)
00658 return false;
00659
00660 /* For custom rule type declarations */
00661 if (rule->listhead != rtn->listhead)
00662 return false;
00663
00664 if (rule->flags != rtn->flags)
00665 return false;
00666
00667 if ( rule->sip and rtn->sip and sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL )
00668 return false;
00669
00670 if ( rule->dip and rtn->dip and sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL )
00671 return false;
00672
00673 /* compare the port group pointers - this prevents confusing src/dst port objects
00674 * with the same port set, and it's quicker. It does assume that we only have
00675 * one port object and pointer for each unique port set...this is handled by the
00676 * parsing and initial port object storage and lookup. This must be consistent during
00677 * the rule parsing phase. - man */
00678 if ( (rule->src_portobject != rtn->src_portobject)
00679 or (rule->dst_portobject != rtn->dst_portobject))
00680 {
00681 return false;
00682 }
00683 return true;
00684 }
00685
00686 static RuleTreeNode* findHeadNode(
00687 SnortConfig* sc, RuleTreeNode* testNode, PolicyId policyId)
00688 {
00689 if ( sc->rtn_hash_table )
00690 {
00691 RuleTreeNodeKey key { testNode, policyId };
00692 return (RuleTreeNode*)sfxhash_find(sc->rtn_hash_table, &key);
00693 }
00694
00695 return nullptr;
00696 }
00697
00698 static void XferHeader(RuleTreeNode* from, RuleTreeNode* to)
00699 {
00700 to->flags = from->flags;
00701 to->type = from->type;
00702 to->sip = from->sip;
00703 to->dip = from->dip;
00704
00705 to->proto = from->proto;
00706
00707 to->src_portobject = from->src_portobject;
00708 to->dst_portobject = from->dst_portobject;
00709 }
00710
00711 /****************************************************************************
00712 * Purpose: Adds RuleTreeNode associated detection functions to the
00713 * current rule's function list
00714 *
00715 * Arguments: *func => function pointer to the detection function
00716 * rtn => pointer to the current rule
00717 ***************************************************************************/
00718 static void AddRuleFuncToList(
00719 int (* rfunc)(Packet*, RuleTreeNode*, struct RuleFpList*, int),
00720 RuleTreeNode* rtn)
00721 {
00722 DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n");
00723 RuleFpList* idx = rtn->rule_func;
00724
00725 if ( !idx )
00726 {
00727 rtn->rule_func = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
00728 rtn->rule_func->RuleHeadFunc = rfunc;
00729 }
00730 else
00731 {
00732 while ( idx->next )
00733 idx = idx->next;
00734
00735 idx->next = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
00736 idx = idx->next;
00737 idx->RuleHeadFunc = rfunc;
00738 }
00739 }
00740
00741 /****************************************************************************
00742 * Purpose: Links the proper IP address testing function to the current RTN
00743 * based on the address, netmask, and addr flags
00744 *
00745 * Arguments: rtn => the pointer to the current rules list entry to attach to
00746 * mode => indicates whether this is a rule for the source
00747 * or destination IP for the rule
00748 ***************************************************************************/
00749 static void AddrToFunc(RuleTreeNode* rtn, int mode)
00750 {
00751 /*
00752 * if IP and mask are both 0, this is a "any" IP and we don't need to
00753 * check it
00754 */
00755 switch (mode)
00756 {
00757 case SRC:
00758 if ((rtn->flags & ANY_SRC_IP) == 0)
00759 {
00760 DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> ");
00761 AddRuleFuncToList(CheckSrcIP, rtn);
00762 }
00763 break;
00764
00765 case DST:
00766 if ((rtn->flags & ANY_DST_IP) == 0)
00767 {
00768 DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> ");
00769 AddRuleFuncToList(CheckDstIP, rtn);
00770 }
00771 break;
00772 }
00773 }
00774
00775 /****************************************************************************
00776 * Purpose: Links in the port analysis function for the current rule
00777 *
00778 * Arguments: rtn => the pointer to the current rules list entry to attach to
00779 * any_flag => accept any port if set
00780 * except_flag => indicates negation (logical NOT) of the test
00781 * mode => indicates whether this is a rule for the source
00782 * or destination port for the rule
00783 ***************************************************************************/
00784 static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mode)
00785 {
00786 /*
00787 * if the any flag is set we don't need to perform any test to match on
00788 * this port
00789 */
00790 if (any_flag)
00791 return;
00792
00793 /* if the except_flag is up, test with the "NotEq" funcs */
00794 if (except_flag)
00795 {
00796 switch (mode)
00797 {
00798 case SRC:
00799 DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortNotEq -> ");
00800 AddRuleFuncToList(CheckSrcPortNotEq, rtn);
00801 break;
00802
00803 case DST:
00804 DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortNotEq -> ");
00805 AddRuleFuncToList(CheckDstPortNotEq, rtn);
00806 break;
00807 }
00808
00809 return;
00810 }
00811 /* default to setting the straight test function */
00812 switch (mode)
00813 {
00814 case SRC:
00815 DebugMessage(DEBUG_CONFIGRULES,"CheckSrcPortEqual -> ");
00816 AddRuleFuncToList(CheckSrcPortEqual, rtn);
00817 break;
00818
00819 case DST:
00820 DebugMessage(DEBUG_CONFIGRULES,"CheckDstPortEqual -> ");
00821 AddRuleFuncToList(CheckDstPortEqual, rtn);
00822 break;
00823 }
00824 }
00825
00826 // Configures the function list for the rule header detection
00827 // functions (addrs and ports)
00828 static void SetupRTNFuncList(RuleTreeNode* rtn)
00829 {
00830 DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n");
00831 DebugMessage(DEBUG_CONFIGRULES,"Functions: ");
00832
00833 if (rtn->flags & BIDIRECTIONAL)
00834 {
00835 DebugMessage(DEBUG_CONFIGRULES,"CheckBidirectional->\n");
00836 AddRuleFuncToList(CheckBidirectional, rtn);
00837 }
00838 else
00839 {
00840 /* Attach the proper port checking function to the function list */
00841 /*
00842 * the in-line "if's" check to see if the "any" or "not" flags have
00843 * been set so the PortToFunc call can determine which port testing
00844 * function to attach to the list
00845 */
00846 PortToFunc(rtn, (rtn->flags & ANY_DST_PORT) ? 1 : 0,
00847 (rtn->flags & EXCEPT_DST_PORT) ? 1 : 0, DST);
00848
00849 /* as above */
00850 PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT) ? 1 : 0,
00851 (rtn->flags & EXCEPT_SRC_PORT) ? 1 : 0, SRC);
00852
00853 /* link in the proper IP address detection function */
00854 AddrToFunc(rtn, SRC);
00855
00856 /* last verse, same as the first (but for dest IP) ;) */
00857 AddrToFunc(rtn, DST);
00858 }
00859
00860 DebugMessage(DEBUG_CONFIGRULES,"RuleListEnd\n");
00861
00862 /* tack the end (success) function to the list */
00863 AddRuleFuncToList(RuleListEnd, rtn);
00864 }
00865
00866 // Process the header block info and add to the block list if necessary
00867 static RuleTreeNode* ProcessHeadNode(
00868 SnortConfig* sc, RuleTreeNode* test_node, ListHead* list)
00869 {
00870 RuleTreeNode* rtn = findHeadNode(
00871 sc, test_node, get_ips_policy()->policy_id);
00872
00873 /* if it doesn't match any of the existing nodes, make a new node and
00874 * stick it at the end of the list */
00875 if ( !rtn )
00876 {
00877 DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n");
00878 head_count++;
00879
00880 rtn = (RuleTreeNode*)snort_calloc(sizeof(RuleTreeNode));
00881 rtn->otnRefCount++;
00882
00883 /* copy the prototype header info into the new header block */
00884 XferHeader(test_node, rtn);
00885
00886 /* initialize the function list for the new RTN */
00887 SetupRTNFuncList(rtn);
00888
00889 /* add link to parent listhead */
00890 rtn->listhead = list;
00891
00892 DebugFormat(DEBUG_CONFIGRULES,
00893 "New Chain head flags = 0x%X\n", rtn->flags);
00894 }
00895 else
00896 {
00897 rtn->otnRefCount++;
00898 FreeRuleTreeNode(test_node);
00899 }
00900
00901 return rtn;
00902 }
00903
00904 // Conditionally removes duplicate SID/GIDs. Keeps duplicate with
00905 // higher revision. If revision is the same, keeps newest rule.
00906 static int mergeDuplicateOtn(
00907 SnortConfig* sc, OptTreeNode* otn_cur,
00908 OptTreeNode* otn_new, RuleTreeNode* rtn_new)
00909 {
00910 if (otn_cur->proto != otn_new->proto)
00911 {
00912 ParseError("GID %u SID %u in rule duplicates previous rule, with different protocol.",
00913 otn_new->sigInfo.gid, otn_new->sigInfo.sid);
00914 return true;
00915 }
00916
00917 RuleTreeNode* rtn_cur = getRtnFromOtn(otn_cur);
00918
00919 if ( rtn_cur and rtn_cur->type != rtn_new->type )
00920 {
00921 ParseError("GID %u SID %u in rule duplicates previous rule, with different type.",
00922 otn_new->sigInfo.gid, otn_new->sigInfo.sid);
00923 return true;
00924 }
00925
00926 if ( otn_new->sigInfo.rev < otn_cur->sigInfo.rev )
00927 {
00928 // current OTN is newer version. Keep current and discard the new one.
00929 // OTN is for new policy group, salvage RTN
00930 deleteRtnFromOtn(otn_new, sc);
00931
00932 ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.",
00933 otn_cur->sigInfo.gid, otn_cur->sigInfo.sid, otn_cur->sigInfo.rev);
00934
00935 // Now free the OTN itself -- this function is also used
00936 // by the hash-table calls out of OtnRemove, so it cannot
00937 // be modified to delete data for rule options
00938 OtnFree(otn_new);
00939
00940 // Add rtn to current otn for the first rule instance in a policy,
00941 // otherwise ignore it
00942 if ( !rtn_cur )
00943 {
00944 addRtnToOtn(sc, otn_cur, rtn_new);
00945 }
00946 else
00947 {
00948 DestroyRuleTreeNode(rtn_new);
00949 }
00950 return true;
00951 }
00952
00953 // delete current rule instance and keep the new one
00954
00955 for ( unsigned i = 0; i < otn_cur->proto_node_num; ++i )
00956 {
00957 RuleTreeNode* rtnTmp2 = deleteRtnFromOtn(otn_cur, i, sc, (rtn_cur != rtn_new));
00958
00959 if ( rtnTmp2 and (i != get_ips_policy()->policy_id) )
00960 {
00961 addRtnToOtn(sc, otn_new, rtnTmp2, i);
00962 }
00963 }
00964
00965 if (rtn_cur)
00966 {
00967 if (SnortConfig::conf_error_out())
00968 {
00969 ParseError("%u:%u:%u duplicates previous rule.",
00970 otn_new->sigInfo.gid, otn_new->sigInfo.sid, otn_new->sigInfo.rev);
00971 return true;
00972 }
00973 else
00974 {
00975 ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.",
00976 otn_new->sigInfo.gid, otn_new->sigInfo.sid, otn_new->sigInfo.rev);
00977 }
00978 }
00979 OtnRemove(sc->otn_map, otn_cur);
00980 DestroyRuleTreeNode(rtn_cur);
00981
00982 return false;
00983 }
00984
00985 int get_rule_count()
00986 { return rule_count; }
00987
00988 void parse_rule_init()
00989 {
00990 rule_count = 0;
00991 detect_rule_count = 0;
00992 builtin_rule_count = 0;
00993 so_rule_count = 0;
00994 head_count = 0;
00995 otn_count = 0;
00996 rule_proto = 0;
00997
00998 memset(&ipCnt, 0, sizeof(ipCnt));
00999 memset(&icmpCnt, 0, sizeof(icmpCnt));
01000 memset(&tcpCnt, 0, sizeof(tcpCnt));
01001 memset(&udpCnt, 0, sizeof(udpCnt));
01002 memset(&svcCnt, 0, sizeof(svcCnt));
01003 }
01004
01005 void parse_rule_term()
01006 { }
01007
01008 void parse_rule_print()
01009 {
01010 if ( !rule_count )
01011 return;
01012
01013 LogLabel("rule counts");
01014 LogCount("total rules loaded", rule_count);
01015 LogCount("text rules", detect_rule_count);
01016 LogCount("builtin rules", builtin_rule_count);
01017 LogCount("so rules", so_rule_count);
01018 LogCount("option chains", otn_count);
01019 LogCount("chain headers", head_count);
01020
01021 unsigned ip = ipCnt.src + ipCnt.dst + ipCnt.any + ipCnt.both;
01022 unsigned icmp = icmpCnt.src + icmpCnt.dst + icmpCnt.any + icmpCnt.both;
01023 unsigned tcp = tcpCnt.src + tcpCnt.dst + tcpCnt.any + tcpCnt.both;
01024 unsigned udp = udpCnt.src + udpCnt.dst + udpCnt.any + udpCnt.both;
01025
01026 if ( !ip and !icmp and !tcp and !udp )
01027 return;
01028
01029 LogLabel("port rule counts");
01030 LogMessage("%8s%8s%8s%8s%8s\n", " ", "tcp", "udp", "icmp", "ip");
01031
01032 if ( tcpCnt.any || udpCnt.any || icmpCnt.any || ipCnt.any )
01033 LogMessage("%8s%8u%8u%8u%8u\n", "any",
01034 tcpCnt.any, udpCnt.any, icmpCnt.any, ipCnt.any);
01035
01036 if ( tcpCnt.src || udpCnt.src || icmpCnt.src || ipCnt.src )
01037 LogMessage("%8s%8u%8u%8u%8u\n", "src",
01038 tcpCnt.src, udpCnt.src, icmpCnt.src, ipCnt.src);
01039
01040 if ( tcpCnt.dst || udpCnt.dst || icmpCnt.dst || ipCnt.dst )
01041 LogMessage("%8s%8u%8u%8u%8u\n", "dst",
01042 tcpCnt.dst, udpCnt.dst, icmpCnt.dst, ipCnt.dst);
01043
01044 if ( tcpCnt.both || udpCnt.both || icmpCnt.both || ipCnt.both )
01045 LogMessage("%8s%8u%8u%8u%8u\n", "both",
01046 tcpCnt.both, udpCnt.both, icmpCnt.both, ipCnt.both);
01047
01048 LogMessage("%8s%8u%8u%8u%8u\n", "total", tcp, udp, icmp, ip);
01049 }
01050
01051 void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
01052 {
01053 memset(&rtn, 0, sizeof(rtn));
01054 rtn.type = get_rule_type(s);
01055
01056 if ( rtn.type == RULE_TYPE__NONE )
01057 {
01058 s_ignore = true;
01059 return;
01060 }
01061 else
01062 {
01063 rtn.listhead = get_rule_list(sc, s);
01064 }
01065
01066 if ( !rtn.listhead )
01067 ParseError("unconfigured rule action '%s'", s);
01068 }
01069
01070 void parse_rule_proto(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
01071 {
01072 if ( s_ignore )
01073 return;
01074
01075 if ( !strcmp(s, "tcp") )
01076 rule_proto = PROTO_BIT__TCP;
01077
01078 else if ( !strcmp(s, "udp") )
01079 rule_proto = PROTO_BIT__UDP;
01080
01081 else if ( !strcmp(s, "icmp") )
01082 rule_proto = PROTO_BIT__ICMP;
01083
01084 else if ( !strcmp(s, "ip") )
01085 rule_proto = PROTO_BIT__IP;
01086
01087 else
01088 // this will allow other protocols like http to have ports
01089 rule_proto = PROTO_BIT__TCP;
01090
01091 rtn.proto = sc->proto_ref->add(s);
01092
01093 if ( rtn.proto <= 0 )
01094 {
01095 ParseError("bad protocol: %s", s);
01096 rule_proto = 0;
01097 }
01098 }
01099
01100 void parse_rule_nets(
01101 SnortConfig* sc, const char* s, bool src, RuleTreeNode& rtn)
01102 {
01103 if ( s_ignore )
01104 return;
01105
01106 ProcessIP(sc, s, &rtn, src ? SRC : DST, 0);
01107 }
01108
01109 void parse_rule_ports(
01110 SnortConfig*, const char* s, bool src, RuleTreeNode& rtn)
01111 {
01112 if ( s_ignore )
01113 return;
01114
01115 IpsPolicy* p = get_ips_policy();
01116
01117 if ( ParsePortList(&rtn, p->portVarTable, p->nonamePortVarTable, s, src ? SRC : DST) )
01118 {
01119 ParseError("bad ports: '%s'", s);
01120 }
01121 }
01122
01123 void parse_rule_dir(SnortConfig*, const char* s, RuleTreeNode& rtn)
01124 {
01125 if ( s_ignore )
01126 return;
01127
01128 if (strcmp(s, "<>") == 0)
01129 rtn.flags |= BIDIRECTIONAL;
01130
01131 else if ( strcmp(s, "->") )
01132 ParseError("illegal direction specifier: %s", s);
01133 }
01134
01135 void parse_rule_opt_begin(SnortConfig* sc, const char* key)
01136 {
01137 if ( s_ignore )
01138 return;
01139
01140 IpsManager::option_begin(sc, key, rule_proto);
01141 }
01142
01143 void parse_rule_opt_set(
01144 SnortConfig* sc, const char* key, const char* opt, const char* val)
01145 {
01146 if ( s_ignore )
01147 return;
01148
01149 IpsManager::option_set(sc, key, opt, val);
01150 }
01151
01152 void parse_rule_opt_end(SnortConfig* sc, const char* key, OptTreeNode* otn)
01153 {
01154 if ( s_ignore )
01155 return;
01156
01157 RuleOptType type = OPT_TYPE_MAX;
01158 IpsManager::option_end(sc, otn, otn->proto, key, type);
01159
01160 if ( type != OPT_TYPE_META )
01161 otn->num_detection_opts++;
01162 }
01163
01164 OptTreeNode* parse_rule_open(SnortConfig* sc, RuleTreeNode& rtn, bool stub)
01165 {
01166 if ( s_ignore )
01167 return nullptr;
01168
01169 if ( stub )
01170 {
01171 parse_rule_proto(sc, "tcp", rtn);
01172 parse_rule_nets(sc, "any", true, rtn);
01173 parse_rule_ports(sc, "any", true, rtn);
01174 parse_rule_dir(sc, "->", rtn);
01175 parse_rule_nets(sc, "any", false, rtn);
01176 parse_rule_ports(sc, "any", false, rtn);
01177 }
01178 OptTreeNode* otn = (OptTreeNode*)snort_calloc(sizeof(OptTreeNode));
01179 otn->state = (OtnState*)snort_calloc(ThreadConfig::get_instance_max(), sizeof(OtnState));
01180
01181 if ( !stub )
01182 otn->sigInfo.gid = GENERATOR_SNORT_ENGINE;
01183
01184 otn->chain_node_number = otn_count;
01185 otn->proto = rtn.proto;
01186 otn->enabled = SnortConfig::get_default_rule_state();
01187
01188 IpsManager::reset_options();
01189
01190 return otn;
01191 }
01192
01193 // return nullptr if nothing left to do
01194 // for so rules, return the detection options and continue parsing
01195 // but if already entered, don't recurse again
01196 const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
01197 {
01198 if ( s_ignore )
01199 {
01200 s_ignore = false;
01201 return nullptr;
01202 }
01203
01204 static bool entered = false;
01205 const char* so_opts = nullptr;
01206
01207 if ( entered )
01208 entered = false;
01209
01210 else if ( otn->soid )
01211 {
01212 so_opts = SoManager::get_so_options(otn->soid);
01213
01214 if ( !so_opts )
01215 ParseError("SO rule %s not loaded.", otn->soid);
01216 else
01217 {
01218 // FIXIT-L gid may be overwritten when set to 3 upon close
01219 otn->sigInfo.gid = GENERATOR_SNORT_SHARED;
01220 entered = true;
01221 return so_opts;
01222 }
01223 }
01224
01225 /* The IPs in the test node get freed in ProcessHeadNode if there is
01226 * already a matching RTN. The portobjects will get freed when the
01227 * port var table is freed */
01228 RuleTreeNode* new_rtn = ProcessHeadNode(sc, &rtn, rtn.listhead);
01229
01230 addRtnToOtn(sc, otn, new_rtn);
01231
01232 OptTreeNode* otn_dup =
01233 OtnLookup(sc->otn_map, otn->sigInfo.gid, otn->sigInfo.sid);
01234
01235 if ( otn_dup )
01236 {
01237 otn->ruleIndex = otn_dup->ruleIndex;
01238
01239 if ( mergeDuplicateOtn(sc, otn_dup, otn, new_rtn) )
01240 {
01241 /* We are keeping the old/dup OTN and trashing the new one
01242 * we just created - it's freed in the remove dup function */
01243 return nullptr;
01244 }
01245 }
01246 otn_count++;
01247 rule_count++;
01248
01249 // FIXIT-L need more reliable way of knowing type of rule instead of
01250 // hard coding these gids do GIDs actually matter anymore (w/o conflict
01251 // with builtins)?
01252
01253 if ( otn->sigInfo.gid == GENERATOR_SNORT_ENGINE )
01254 {
01255 otn->sigInfo.text_rule = true;
01256 detect_rule_count++;
01257 }
01258 else if ( otn->sigInfo.gid == GENERATOR_SNORT_SHARED )
01259 {
01260 otn->sigInfo.text_rule = true;
01261 so_rule_count++;
01262 }
01263 else if ( ModuleManager::gid_in_use(otn->sigInfo.gid) )
01264 {
01265 if ( otn->num_detection_opts )
01266 ParseError("%u:%u builtin rules do not support detection options",
01267 otn->sigInfo.gid, otn->sigInfo.sid);
01268
01269 otn->sigInfo.text_rule = false;
01270 builtin_rule_count++;
01271 }
01272
01273 if ( !otn_dup )
01274 otn->ruleIndex = parser_get_rule_index(otn->sigInfo.gid, otn->sigInfo.sid);
01275
01276 OptFpList* fpl = AddOptFuncToList(OptListEnd, otn);
01277 fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
01278
01279 validate_fast_pattern(otn);
01280 OtnLookupAdd(sc->otn_map, otn);
01281
01282 if ( is_service_protocol(otn->proto) )
01283 add_service_to_otn(sc, otn, sc->proto_ref->get_name(otn->proto));
01284
01285 /*
01286 * The src/dst port parsing must be done before the Head Nodes are processed, since they must
01287 * compare the ports/port_objects to find the right rtn list to add the otn rule to.
01288 *
01289 * After otn processing we can finalize port object processing for this rule
01290 */
01291 if ( FinishPortListRule(
01292 sc->port_tables, new_rtn, otn, rtn.proto, sc->fast_pattern_config) )
01293 ParseError("Failed to finish a port list rule.");
01294
01295 // Clear ips_option vars
01296 ClearIpsOptionsVars();
01297
01298 return nullptr;
01299 }
01300
END OF CODE