00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2016-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018
00019 // packet_capture.cc author Carter Waxman <cwaxman@cisco.com>
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include "packet_capture.h"
00026
00027 #include <pcap.h>
00028 #include <sfbpf.h>
00029
00030 #include "framework/inspector.h"
00031 #include "log/messages.h"
00032 #include "protocols/packet.h"
00033
00034 #ifdef UNIT_TEST
00035 #include "catch/catch.hpp"
00036 #endif
00037
00038 #include "capture_module.h"
00039
00040 using namespace std;
00041
00042 #define FILE_NAME "packet_capture.pcap"
00043 #define SNAP_LEN 65535
00044
00045 static CaptureConfig config;
00046
00047 static THREAD_LOCAL pcap_t* pcap = nullptr;
00048 static THREAD_LOCAL pcap_dumper_t* dumper = nullptr;
00049 static THREAD_LOCAL struct sfbpf_program bpf;
00050
00051 static inline bool capture_initialized()
00052 { return dumper != nullptr; }
00053
00054 void packet_capture_enable(const string& f)
00055 {
00056 if ( !config.enabled )
00057 {
00058 config.filter = f;
00059 config.enabled = true;
00060 }
00061 else
00062 WarningMessage("Conflicting packet capture already in progress.\n");
00063 }
00064
00065 void packet_capture_disable()
00066 {
00067 config.enabled = false;
00068 LogMessage("Packet capture disabled\n");
00069 }
00070
00071 //-------------------------------------------------------------------------
00072 // class stuff
00073 //-------------------------------------------------------------------------
00074
00075 class PacketCapture : public Inspector
00076 {
00077 public:
00078 PacketCapture(CaptureModule*);
00079
00080 void eval(Packet*) override;
00081 void tterm() override { capture_term(); }
00082
00083 protected:
00084 virtual bool capture_init();
00085 virtual void capture_term();
00086 virtual pcap_dumper_t* open_dump(pcap_t*, const char*);
00087 virtual void write_packet(Packet* p);
00088 };
00089
00090 PacketCapture::PacketCapture(CaptureModule* m)
00091 { m->get_config(config); }
00092
00093 void PacketCapture::eval(Packet* p)
00094 {
00095
00096 new_invoked_inspector(5, p, 0);
00097 if ( config.enabled )
00098 {
00099 if ( !capture_initialized() )
00100 if ( !capture_init() )
00101 return;
00102
00103 if ( !bpf.bf_insns || sfbpf_filter(bpf.bf_insns, p->pkt,
00104 p->pkth->caplen, p->pkth->pktlen) )
00105 {
00106 write_packet(p);
00107 cap_count_stats.matched++;
00108 }
00109
00110 cap_count_stats.checked++;
00111 }
00112 else if ( capture_initialized() )
00113 capture_term();
00114 }
00115
00116 bool PacketCapture::capture_init()
00117 {
00118 if ( sfbpf_compile(SNAP_LEN, DLT_EN10MB, &bpf,
00119 config.filter.c_str(), 1, 0) >= 0 )
00120 {
00121 if ( sfbpf_validate(bpf.bf_insns, bpf.bf_len) )
00122 {
00123 string fname;
00124 get_instance_file(fname, FILE_NAME);
00125
00126 pcap = pcap_open_dead(DLT_EN10MB, SNAP_LEN);
00127 dumper = open_dump(pcap, fname.c_str());
00128
00129 if ( dumper )
00130 return true;
00131 else
00132 WarningMessage("Could not initialize dump file\n");
00133 }
00134 else
00135 WarningMessage("Unable to validate BPF filter\n");
00136 }
00137 else
00138 WarningMessage("Unable to compile BPF filter\n");
00139
00140 packet_capture_disable();
00141 capture_term();
00142 return false;
00143 }
00144
00145 pcap_dumper_t* PacketCapture::open_dump(pcap_t* pcap, const char* fname)
00146 { return pcap_dump_open(pcap, fname); }
00147
00148 void PacketCapture::capture_term()
00149 {
00150 if ( dumper )
00151 {
00152 pcap_dump_close(dumper);
00153 dumper = nullptr;
00154 }
00155 if ( pcap )
00156 {
00157 free(pcap);
00158 pcap = nullptr;
00159 }
00160 sfbpf_freecode(&bpf);
00161 }
00162
00163 void PacketCapture::write_packet(Packet* p)
00164 {
00165 //DAQ_PktHdr_t is compatible with pcap_pkthdr
00166 pcap_dump((unsigned char*)dumper, (const pcap_pkthdr*)p->pkth, p->pkt);
00167 pcap_dump_flush(dumper);
00168 }
00169
00170 //-------------------------------------------------------------------------
00171 // api stuff
00172 //-------------------------------------------------------------------------
00173
00174 static Module* mod_ctor()
00175 { return new CaptureModule; }
00176
00177 static void mod_dtor(Module* m)
00178 { delete m; }
00179
00180 static Inspector* pc_ctor(Module* m)
00181 { return new PacketCapture((CaptureModule*)m); }
00182
00183 static void pc_dtor(Inspector* p)
00184 { delete p; }
00185
00186 static const InspectApi pc_api =
00187 {
00188 {
00189 PT_INSPECTOR,
00190 sizeof(InspectApi),
00191 INSAPI_VERSION,
00192 0,
00193 API_RESERVED,
00194 API_OPTIONS,
00195 CAPTURE_NAME,
00196 CAPTURE_HELP,
00197 mod_ctor,
00198 mod_dtor
00199 },
00200 IT_PACKET,
00201 (uint16_t)PktType::ANY,
00202 nullptr, // buffers
00203 nullptr, // service
00204 nullptr, // pinit
00205 nullptr, // pterm
00206 nullptr, // tinit
00207 nullptr, // tterm
00208 pc_ctor,
00209 pc_dtor,
00210 nullptr, // ssn
00211 nullptr // reset
00212 };
00213
00214 #ifdef BUILDING_SO
00215 SO_PUBLIC const BaseApi* snort_plugins[] =
00216 #else
00217 const BaseApi* nin_packet_capture[] =
00218 #endif
00219 {
00220 &pc_api.base,
00221 nullptr
00222 };
00223
00224 #ifdef UNIT_TEST
00225 static Packet* init_null_packet()
00226 {
00227 static Packet p(false);
00228 static DAQ_PktHdr_t h;
00229
00230 p.pkt = nullptr;
00231 p.pkth = &h;
00232 h.caplen = 0;
00233 h.pktlen = 0;
00234
00235 return &p;
00236 }
00237
00238 class MockPacketCapture : public PacketCapture
00239 {
00240 public:
00241 bool write_packet_called = false;
00242 vector<Packet*> pcap;
00243
00244 MockPacketCapture(CaptureModule* m) : PacketCapture(m) {}
00245
00246 protected:
00247 pcap_dumper_t* open_dump(pcap_t*, const char*) override
00248 { return (pcap_dumper_t*)1; }
00249
00250 void write_packet(Packet* p) override
00251 {
00252 pcap.push_back(p);
00253 write_packet_called = true;
00254 }
00255
00256 void capture_term() override
00257 {
00258 dumper = nullptr;
00259 PacketCapture::capture_term();
00260 }
00261 };
00262
00263
00264 TEST_CASE("toggle", "[PacketCapture]")
00265 {
00266 auto null_packet = init_null_packet();
00267
00268 CaptureModule mod;
00269 MockPacketCapture cap(&mod);
00270
00271 cap.write_packet_called = false;
00272 cap.eval(null_packet);
00273 CHECK ( !cap.write_packet_called );
00274
00275 cap.write_packet_called = false;
00276 packet_capture_enable("");
00277 cap.eval(null_packet);
00278 CHECK ( cap.write_packet_called );
00279
00280 cap.write_packet_called = false;
00281 packet_capture_disable();
00282 cap.eval(null_packet);
00283 CHECK ( !cap.write_packet_called );
00284 }
00285
00286 TEST_CASE("lazy init", "[PacketCapture]")
00287 {
00288 auto null_packet = init_null_packet();
00289
00290 auto mod = (CaptureModule*)mod_ctor();
00291 auto real_cap = (PacketCapture*)pc_ctor(mod);
00292
00293 CHECK ( !capture_initialized() );
00294
00295 real_cap->eval(null_packet);
00296 CHECK ( !capture_initialized() );
00297
00298 pc_dtor(real_cap);
00299 MockPacketCapture cap(mod);
00300
00301 packet_capture_enable("");
00302 CHECK ( !capture_initialized() );
00303
00304 cap.eval(null_packet);
00305 CHECK ( capture_initialized() );
00306
00307 packet_capture_disable();
00308 CHECK ( capture_initialized() );
00309
00310 cap.eval(null_packet);
00311 CHECK ( !capture_initialized() );
00312
00313 mod_dtor(mod);
00314 }
00315
00316 TEST_CASE("blank filter", "[PacketCapture]")
00317 {
00318 auto null_packet = init_null_packet();
00319
00320 const uint8_t cooked[] = "AbCdEfGhIjKlMnOpQrStUvWxYz";
00321
00322 Packet p(false);
00323 DAQ_PktHdr_t daq_hdr;
00324 p.pkt = cooked;
00325 p.pkth = &daq_hdr;
00326
00327 daq_hdr.caplen = sizeof(cooked);
00328 daq_hdr.pktlen = sizeof(cooked);
00329
00330 CaptureModule mod;
00331 MockPacketCapture cap(&mod);
00332
00333 packet_capture_enable("");
00334 cap.eval(&p);
00335
00336 REQUIRE ( cap.pcap.size() );
00337 CHECK ( cap.pcap[0] == &p );
00338
00339 packet_capture_disable();
00340 cap.eval(null_packet);
00341 }
00342
00343 TEST_CASE("bad filter", "[PacketCapture]")
00344 {
00345 auto null_packet = init_null_packet();
00346
00347 CaptureModule mod;
00348 MockPacketCapture cap(&mod);
00349
00350 packet_capture_enable("this is garbage");
00351 cap.eval(null_packet);
00352 CHECK ( !capture_initialized() );
00353
00354 packet_capture_enable(
00355 "port 0 "
00356 "port 1 "
00357 "port 2 "
00358 "port 3 "
00359 "port 4 "
00360 "port 5 "
00361 "port 6 "
00362 "port 7 "
00363 "port 8 "
00364 "port 9 "
00365 "port 10 "
00366 "port 11 "
00367 "port 12 "
00368 "port 13 "
00369 "port 14 "
00370 "port 15 "
00371 "port 16 "
00372 "port 17 "
00373 "port 18 "
00374 "port 19 "
00375 );
00376 cap.eval(null_packet);
00377 CHECK ( !capture_initialized() );
00378 }
00379
00380 TEST_CASE("bpf filter", "[PacketCapture]")
00381 {
00382 auto null_packet = init_null_packet();
00383
00384 const uint8_t match[] =
00385 //ethernet
00386 "\xfc\x4d\xd4\x3d\xdc\xb8\x3c\x08\xf6\x2d\x6d\xbf\x08\x00"
00387
00388 //ipv4
00389 "\x45\x00\x00\x14\x96\x22\x40\x00\x39\x06\xb1\xeb\x0a\x52\xf0\x52"
00390 "\x0a\x96";
00391
00392 const uint8_t non_match[] =
00393 //ethernet
00394 "\xfc\x4d\xd4\x3d\xdc\xb8\x3c\x08\xf6\x2d\x6d\xbf\x08\x00"
00395
00396 //ipv4
00397 "\x45\x00\x00\x14\x96\x22\x40\x00\x39\x06\xb1\xeb\x0b\x52\xf0\x52"
00398 "\x0a\x96";
00399
00400 Packet p_match(false), p_non_match(false);
00401 DAQ_PktHdr_t daq_hdr;
00402
00403 p_match.pkth = &daq_hdr;
00404 p_non_match.pkth = &daq_hdr;
00405
00406 p_match.pkt = match;
00407 p_non_match.pkt = non_match;
00408
00409 daq_hdr.caplen = sizeof(match);
00410 daq_hdr.pktlen = sizeof(match);
00411
00412 CaptureModule mod;
00413 MockPacketCapture cap(&mod);
00414
00415 cap_count_stats.checked = 0;
00416 cap_count_stats.matched = 0;
00417
00418 packet_capture_enable("ip host 10.82.240.82");
00419 packet_capture_enable(""); //Test double-enable guard
00420
00421 cap.write_packet_called = false;
00422 cap.eval(&p_match);
00423 CHECK ( cap.write_packet_called );
00424
00425 cap.write_packet_called = false;
00426 cap.eval(&p_non_match);
00427 CHECK ( !cap.write_packet_called );
00428
00429 cap.write_packet_called = false;
00430 cap.eval(&p_match);
00431 CHECK ( cap.write_packet_called );
00432
00433 CHECK ( (cap_count_stats.checked == 3) );
00434 CHECK ( (cap_count_stats.matched == 2) );
00435
00436 REQUIRE ( (cap.pcap.size() >= 2) );
00437 CHECK ( (cap.pcap.size() == 2) );
00438 CHECK ( cap.pcap[0] == &p_match );
00439 CHECK ( cap.pcap[1] == &p_match );
00440
00441 packet_capture_disable();
00442 cap.eval(null_packet);
00443 }
00444 #endif
END OF CODE