00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2002-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 // ips_flow.cc derived from sp_clientserver.c by Martin Roesch
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include "ips_flow.h"
00026
00027 #include "detection/detection_defines.h"
00028 #include "detection/treenodes.h"
00029 #include "framework/ips_option.h"
00030 #include "framework/module.h"
00031 #include "hash/sfhashfcn.h"
00032 #include "log/messages.h"
00033 #include "profiler/profiler.h"
00034 #include "protocols/packet.h"
00035 #include "target_based/snort_protocols.h"
00036
00037 #define s_name "flow"
00038
00039 static THREAD_LOCAL ProfileStats flowCheckPerfStats;
00040
00041 #define ONLY_STREAM 0x01
00042 #define ONLY_FRAG 0x02
00043 #define IGNORE_STREAM 0x01
00044 #define IGNORE_FRAG 0x02
00045
00046 struct FlowCheckData
00047 {
00048 uint8_t from_server;
00049 uint8_t from_client;
00050 uint8_t ignore_reassembled;
00051 uint8_t only_reassembled;
00052 uint8_t stateless;
00053 uint8_t established;
00054 uint8_t unestablished;
00055 };
00056
00057 class FlowCheckOption : public IpsOption
00058 {
00059 public:
00060 FlowCheckOption(const FlowCheckData& c) : IpsOption(s_name)
00061 { config = c; }
00062
00063 uint32_t hash() const override;
00064 bool operator==(const IpsOption&) const override;
00065
00066 int eval(Cursor&, Packet*) override;
00067
00068 //private:
00069 FlowCheckData config; // FIXIT-L privatize
00070 };
00071
00072 //-------------------------------------------------------------------------
00073 // class methods
00074 //-------------------------------------------------------------------------
00075
00076 uint32_t FlowCheckOption::hash() const
00077 {
00078 uint32_t a,b,c;
00079 const FlowCheckData* data = &config;
00080
00081 a = data->from_server | (data->from_client << 16);
00082 b = data->ignore_reassembled | (data->only_reassembled << 16);
00083 c = data->stateless | (data->established << 16);
00084
00085 mix(a,b,c);
00086 mix_str(a,b,c,get_name());
00087
00088 a += data->unestablished;
00089 finalize(a,b,c);
00090
00091 return c;
00092 }
00093
00094 bool FlowCheckOption::operator==(const IpsOption& ips) const
00095 {
00096 if ( strcmp(get_name(), ips.get_name()) )
00097 return false;
00098
00099 const FlowCheckOption& rhs = (const FlowCheckOption&)ips;
00100 const FlowCheckData* left = &config;
00101 const FlowCheckData* right = &rhs.config;
00102
00103 if (( left->from_server == right->from_server) &&
00104 ( left->from_client == right->from_client) &&
00105 ( left->ignore_reassembled == right->ignore_reassembled) &&
00106 ( left->only_reassembled == right->only_reassembled) &&
00107 ( left->stateless == right->stateless) &&
00108 ( left->established == right->established) &&
00109 ( left->unestablished == right->unestablished))
00110 {
00111 return true;
00112 }
00113
00114 return false;
00115 }
00116
00117 int FlowCheckOption::eval(Cursor&, Packet* p)
00118 {
00119 Profile profile(flowCheckPerfStats);
00120
00121 FlowCheckData* fcd = &config;
00122
00123 // Check established/unestablished first
00124 {
00125 if ((fcd->established == 1) && !(p->packet_flags & PKT_STREAM_EST))
00126 {
00127 // This option requires an established connection and it isn't
00128 // in that state yet, so no match.
00129 return DETECTION_OPTION_NO_MATCH;
00130 }
00131 else if ((fcd->unestablished == 1) && (p->packet_flags & PKT_STREAM_EST))
00132 {
00133 // We're looking for an unestablished stream, and this is
00134 // established, so don't continue processing.
00135 return DETECTION_OPTION_NO_MATCH;
00136 }
00137 }
00138
00139 // Now check from client
00140 if (fcd->from_client)
00141 {
00142 {
00143 if (!p->is_from_client() && p->is_from_server())
00144 {
00145 // No match on from_client
00146 return DETECTION_OPTION_NO_MATCH;
00147 }
00148 }
00149 }
00150
00151 // And from server
00152 if (fcd->from_server)
00153 {
00154 {
00155 if (!p->is_from_server() && p->is_from_client())
00156 {
00157 // No match on from_server
00158 return DETECTION_OPTION_NO_MATCH;
00159 }
00160 }
00161 }
00162
00163 // ...ignore_reassembled
00164 if (fcd->ignore_reassembled & IGNORE_STREAM)
00165 {
00166 if (p->packet_flags & PKT_REBUILT_STREAM)
00167 {
00168 return DETECTION_OPTION_NO_MATCH;
00169 }
00170 }
00171
00172 if (fcd->ignore_reassembled & IGNORE_FRAG)
00173 {
00174 if (p->packet_flags & PKT_REBUILT_FRAG)
00175 {
00176 return DETECTION_OPTION_NO_MATCH;
00177 }
00178 }
00179
00180 // ...only_reassembled
00181 if (fcd->only_reassembled & ONLY_STREAM)
00182 {
00183 if ( !p->has_paf_payload() )
00184 {
00185 return DETECTION_OPTION_NO_MATCH;
00186 }
00187 }
00188
00189 if (fcd->only_reassembled & ONLY_FRAG)
00190 {
00191 if (!(p->packet_flags & PKT_REBUILT_FRAG))
00192 {
00193 return DETECTION_OPTION_NO_MATCH;
00194 }
00195 }
00196
00197 return DETECTION_OPTION_MATCH;
00198 }
00199
00200 //-------------------------------------------------------------------------
00201 // public methods
00202 //-------------------------------------------------------------------------
00203
00204 int OtnFlowFromServer(OptTreeNode* otn)
00205 {
00206 FlowCheckOption* fco =
00207 (FlowCheckOption*)get_rule_type_data(otn, s_name);
00208
00209 if (fco )
00210 {
00211 if ( fco->config.from_server )
00212 return 1;
00213 }
00214 return 0;
00215 }
00216
00217 int OtnFlowFromClient(OptTreeNode* otn)
00218 {
00219 FlowCheckOption* fco =
00220 (FlowCheckOption*)get_rule_type_data(otn, s_name);
00221
00222 if (fco )
00223 {
00224 if ( fco->config.from_client )
00225 return 1;
00226 }
00227 return 0;
00228 }
00229
00230 //-------------------------------------------------------------------------
00231 // support methods
00232 //-------------------------------------------------------------------------
00233
00234 static void flow_verify(FlowCheckData* fcd)
00235 {
00236 if (fcd->from_client && fcd->from_server)
00237 {
00238 ParseError("can't use both from_client and flow_from server");
00239 return;
00240 }
00241
00242 if ((fcd->ignore_reassembled & IGNORE_STREAM) && (fcd->only_reassembled & ONLY_STREAM))
00243 {
00244 ParseError("can't use no_stream and only_stream");
00245 return;
00246 }
00247
00248 if ((fcd->ignore_reassembled & IGNORE_FRAG) && (fcd->only_reassembled & ONLY_FRAG))
00249 {
00250 ParseError("can't use no_frag and only_frag");
00251 return;
00252 }
00253
00254 if (fcd->stateless && (fcd->from_client || fcd->from_server))
00255 {
00256 ParseError("can't use flow: stateless option with other options");
00257 return;
00258 }
00259
00260 if (fcd->stateless && fcd->established)
00261 {
00262 ParseError("can't specify established and stateless "
00263 "options in same rule");
00264 return;
00265 }
00266
00267 if (fcd->stateless && fcd->unestablished)
00268 {
00269 ParseError("can't specify unestablished and stateless "
00270 "options in same rule");
00271 return;
00272 }
00273
00274 if (fcd->established && fcd->unestablished)
00275 {
00276 ParseError("can't specify unestablished and established "
00277 "options in same rule");
00278 return;
00279 }
00280 }
00281
00282 //-------------------------------------------------------------------------
00283 // module
00284 //-------------------------------------------------------------------------
00285
00286 static const Parameter s_params[] =
00287 {
00288 { "to_client", Parameter::PT_IMPLIED, nullptr, nullptr,
00289 "match on server responses" },
00290
00291 { "to_server", Parameter::PT_IMPLIED, nullptr, nullptr,
00292 "match on client requests" },
00293
00294 { "from_client", Parameter::PT_IMPLIED, nullptr, nullptr,
00295 "same as to_server" },
00296
00297 { "from_server", Parameter::PT_IMPLIED, nullptr, nullptr,
00298 "same as to_client" },
00299
00300 { "established", Parameter::PT_IMPLIED, nullptr, nullptr,
00301 "match only during data transfer phase" },
00302
00303 { "not_established", Parameter::PT_IMPLIED, nullptr, nullptr,
00304 "match only outside data transfer phase" },
00305
00306 { "stateless", Parameter::PT_IMPLIED, nullptr, nullptr,
00307 "match regardless of stream state" },
00308
00309 { "no_stream", Parameter::PT_IMPLIED, nullptr, nullptr,
00310 "match on raw packets only" },
00311
00312 { "only_stream", Parameter::PT_IMPLIED, nullptr, nullptr,
00313 "match on reassembled packets only" },
00314
00315 { "no_frag", Parameter::PT_IMPLIED, nullptr, nullptr,
00316 "match on raw packets only" },
00317
00318 { "only_frag", Parameter::PT_IMPLIED, nullptr, nullptr,
00319 "match on defragmented packets only" },
00320
00321 { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
00322 };
00323
00324 #define s_help \
00325 "rule option to check session properties"
00326
00327 class FlowModule : public Module
00328 {
00329 public:
00330 FlowModule() : Module(s_name, s_help, s_params) { }
00331
00332 bool begin(const char*, int, SnortConfig*) override;
00333 bool set(const char*, Value&, SnortConfig*) override;
00334
00335 ProfileStats* get_profile() const override
00336 { return &flowCheckPerfStats; }
00337
00338 Usage get_usage() const override
00339 { return DETECT; }
00340
00341 public:
00342 FlowCheckData data;
00343 };
00344
00345 bool FlowModule::begin(const char*, int, SnortConfig*)
00346 {
00347 memset(&data, 0, sizeof(data));
00348 return true;
00349 }
00350
00351 bool FlowModule::set(const char*, Value& v, SnortConfig*)
00352 {
00353 if ( v.is("to_server") )
00354 data.from_client = 1;
00355
00356 else if ( v.is("to_client") )
00357 data.from_server = 1;
00358
00359 else if ( v.is("from_server") )
00360 data.from_server = 1;
00361
00362 else if ( v.is("from_client") )
00363 data.from_client = 1;
00364
00365 else if ( v.is("stateless") )
00366 data.stateless = 1;
00367
00368 else if ( v.is("established") )
00369 data.established = 1;
00370
00371 else if ( v.is("not_established") )
00372 data.unestablished = 1;
00373
00374 else if ( v.is("no_stream") )
00375 data.ignore_reassembled |= IGNORE_STREAM;
00376
00377 else if ( v.is("only_stream") )
00378 data.only_reassembled |= ONLY_STREAM;
00379
00380 else if ( v.is("no_frag") )
00381 data.ignore_reassembled |= IGNORE_FRAG;
00382
00383 else if ( v.is("only_frag") )
00384 data.only_reassembled |= ONLY_FRAG;
00385
00386 else
00387 return false;
00388
00389 flow_verify(&data);
00390 return true;
00391 }
00392
00393 //-------------------------------------------------------------------------
00394 // api methods
00395 //-------------------------------------------------------------------------
00396
00397 static Module* mod_ctor()
00398 {
00399 return new FlowModule;
00400 }
00401
00402 static void mod_dtor(Module* m)
00403 {
00404 delete m;
00405 }
00406
00407 static IpsOption* flow_ctor(Module* p, OptTreeNode* otn)
00408 {
00409 FlowModule* m = (FlowModule*)p;
00410
00411 if ( m->data.stateless )
00412 otn->stateless = 1;
00413
00414 if ( m->data.established )
00415 otn->established = 1;
00416
00417 if ( m->data.unestablished )
00418 otn->unestablished = 1;
00419
00420 if (otn->proto == SNORT_PROTO_ICMP)
00421 {
00422 if ( (m->data.only_reassembled != ONLY_FRAG) &&
00423 (m->data.ignore_reassembled != IGNORE_FRAG) )
00424 {
00425 ParseError("Cannot check flow connection for ICMP traffic");
00426 return nullptr;
00427 }
00428 }
00429 return new FlowCheckOption(m->data);
00430 }
00431
00432 static void flow_dtor(IpsOption* p)
00433 {
00434 delete p;
00435 }
00436
00437 static const IpsApi flow_api =
00438 {
00439 {
00440 PT_IPS_OPTION,
00441 sizeof(IpsApi),
00442 IPSAPI_VERSION,
00443 0,
00444 API_RESERVED,
00445 API_OPTIONS,
00446 s_name,
00447 s_help,
00448 mod_ctor,
00449 mod_dtor
00450 },
00451 OPT_TYPE_DETECTION,
00452 1, 0,
00453 nullptr,
00454 nullptr,
00455 nullptr,
00456 nullptr,
00457 flow_ctor,
00458 flow_dtor,
00459 nullptr
00460 };
00461
00462 const BaseApi* ips_flow = &flow_api.base;
00463
END OF CODE