diff --git a/scripts/base/files/extract/main.zeek b/scripts/base/files/extract/main.zeek index 211b65536e..24cdb151c9 100644 --- a/scripts/base/files/extract/main.zeek +++ b/scripts/base/files/extract/main.zeek @@ -9,12 +9,17 @@ export { ## The default max size for extracted files (they won't exceed this ## number of bytes). A value of zero means unlimited. - ## - ## Note: Holes in files do not count towards these limits. Files with - ## holes are created as sparse files on disk. This means that their - ## apparent size can exceed this limit. option default_limit = 0; + ## This setting configures if the file extract limit is inclusive + ## of missing bytes. By default, missing bytes do count towards the + ## limit. + ## Setting this option to false changes this behavior so that missing + ## bytes no longer count towards these limits. Files with + ## missing bytes are created as sparse files on disk. Their apparent size + ## can exceed this file size limit. + option default_limit_includes_missing = T; + redef record Files::Info += { ## Local filename of extracted file. extracted: string &optional &log; @@ -41,6 +46,14 @@ export { ## :zeek:see:`FileExtract::set_limit` is called to increase the ## limit. A value of zero means "no limit". extract_limit: count &default=default_limit; + ## By default, missing bytes in files count towards the extract file size. + ## Missing bytes can, e.g., occur due to missed traffic, or offsets + ## used when downloading files. + ## Setting this option to false changes this behavior so that holes + ## in files do no longer count towards these limits. Files with + ## holes are created as sparse files on disk. Their apparent size + ## can exceed this file size limit. + extract_limit_includes_missing: bool &default=default_limit_includes_missing; }; ## Sets the maximum allowed extracted file size. diff --git a/src/file_analysis/analyzer/extract/Extract.cc b/src/file_analysis/analyzer/extract/Extract.cc index 284683f51e..9aad2863ac 100644 --- a/src/file_analysis/analyzer/extract/Extract.cc +++ b/src/file_analysis/analyzer/extract/Extract.cc @@ -13,9 +13,10 @@ namespace zeek::file_analysis::detail { Extract::Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename, - uint64_t arg_limit) + uint64_t arg_limit, bool arg_limit_includes_missing) : file_analysis::Analyzer(file_mgr->GetComponentTag("EXTRACT"), std::move(args), file), - filename(arg_filename), limit(arg_limit), written(0) + filename(arg_filename), limit(arg_limit), written(0), + limit_includes_missing(arg_limit_includes_missing) { char buf[128]; file_stream = fopen(filename.data(), "wb"); @@ -60,11 +61,14 @@ file_analysis::Analyzer* Extract::Instantiate(RecordValPtr args, file_analysis:: { const auto& fname = get_extract_field_val(args, "extract_filename"); const auto& limit = get_extract_field_val(args, "extract_limit"); + const auto& extract_limit_includes_missing = get_extract_field_val( + args, "extract_limit_includes_missing"); - if ( ! fname || ! limit ) + if ( ! fname || ! limit || ! extract_limit_includes_missing ) return nullptr; - return new Extract(std::move(args), file, fname->AsString()->CheckString(), limit->AsCount()); + return new Extract(std::move(args), file, fname->AsString()->CheckString(), limit->AsCount(), + extract_limit_includes_missing->AsBool()); } /** @@ -153,6 +157,29 @@ bool Extract::Undelivered(uint64_t offset, uint64_t len) if ( ! file_stream ) return false; + if ( limit_includes_missing ) + { + uint64_t towrite = 0; + bool limit_exceeded = check_limit_exceeded(limit, written, len, &towrite); + // if the limit is exceeded, we have to raise the event. This gives scripts the opportunity + // to raise the limit. + if ( limit_exceeded && file_extraction_limit ) + { + file_analysis::File* f = GetFile(); + f->FileEvent(file_extraction_limit, + {f->ToVal(), GetArgs(), val_mgr->Count(limit), val_mgr->Count(len)}); + // we have to check again if the limit is still exceedee + limit_exceeded = check_limit_exceeded(limit, written, len, &towrite); + } + + // if the limit is exceeded, abort and don't do anything - no reason to seek. + if ( limit_exceeded ) + return false; + + // if we don't skip holes, count this hole against the write limit + written += len; + } + if ( fseek(file_stream, len + offset, SEEK_SET) != 0 ) { char buf[128]; diff --git a/src/file_analysis/analyzer/extract/Extract.h b/src/file_analysis/analyzer/extract/Extract.h index 96a18c49f1..60249741ce 100644 --- a/src/file_analysis/analyzer/extract/Extract.h +++ b/src/file_analysis/analyzer/extract/Extract.h @@ -65,15 +65,17 @@ protected: * @param arg_filename a file system path which specifies the local file * to which the contents of the file will be extracted/written. * @param arg_limit the maximum allowed file size. + * @param arg_limit_includes_missing missing bytes count towards limit if true. */ Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename, - uint64_t arg_limit); + uint64_t arg_limit, bool arg_limit_includes_missing); private: std::string filename; FILE* file_stream; uint64_t limit; // the file extraction limit uint64_t written; // how many bytes we have written so far + bool limit_includes_missing; // do count missing bytes against limit if true }; } // namespace zeek::file_analysis::detail diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index d7242fc762..986b4f35c7 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -551,6 +551,7 @@ 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (FTP::max_reply_msg_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (FTP::max_user_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (FileExtract::default_limit, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> +0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (FileExtract::default_limit_includes_missing, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Files::enable_reassembler, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (GridFTP::max_time, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (GridFTP::size_threshold, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> @@ -2178,6 +2179,7 @@ 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (FTP::max_reply_msg_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (FTP::max_user_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (FileExtract::default_limit, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) +0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (FileExtract::default_limit_includes_missing, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Files::enable_reassembler, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (GridFTP::max_time, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (GridFTP::size_threshold, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) @@ -3804,6 +3806,7 @@ 0.000000 | HookCallFunction Option::set_change_handler(FTP::max_reply_msg_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(FTP::max_user_length, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(FileExtract::default_limit, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) +0.000000 | HookCallFunction Option::set_change_handler(FileExtract::default_limit_includes_missing, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(Files::enable_reassembler, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(GridFTP::max_time, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(GridFTP::size_threshold, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/1.out b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/1.out new file mode 100644 index 0000000000..0ef9544205 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/1.out @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +file_extraction_limit, 10, 2147483648 diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/2.out b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/2.out new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/2.out @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/3.out b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/3.out new file mode 100644 index 0000000000..4f3357a79c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/3.out @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +file_extraction_limit, 1, 2 diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/extract_files.1 b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/extract_files.1 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-1.log b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-1.log new file mode 100644 index 0000000000..127d2603f7 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-1.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path files +#open XXXX-XX-XX-XX-XX-XX +#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid extracted extracted_cutoff extracted_size +#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string bool count +XXXXXXXXXX.XXXXXX Fg5gNDmaUhHwqjbp8 CHhAvVGS1DHFjwGM9 192.168.65.2 53720 91.189.91.123 80 HTTP 0 EXTRACT - - 0.000000 F F 2 5037662208 2147483648 0 T - 1 T 10 +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-2.log b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-2.log new file mode 100644 index 0000000000..ffe8bed0ad --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-2.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path files +#open XXXX-XX-XX-XX-XX-XX +#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid extracted extracted_cutoff extracted_size +#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string bool count +XXXXXXXXXX.XXXXXX Fg5gNDmaUhHwqjbp8 CHhAvVGS1DHFjwGM9 192.168.65.2 53720 91.189.91.123 80 HTTP 0 EXTRACT - - 0.000000 F F 2 5037662208 2147483648 0 T - 2 F - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-3.log b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-3.log new file mode 100644 index 0000000000..c2d233c3ec --- /dev/null +++ b/testing/btest/Baseline/scripts.base.files.extract.limit-large-hole/files-3.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path files +#open XXXX-XX-XX-XX-XX-XX +#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid extracted extracted_cutoff extracted_size +#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string bool count +XXXXXXXXXX.XXXXXX Fg5gNDmaUhHwqjbp8 CHhAvVGS1DHFjwGM9 192.168.65.2 53720 91.189.91.123 80 HTTP 0 EXTRACT - - 0.000000 F F 2 5037662208 2147483648 0 T - 3 T 1 +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/spicy.file-analyzer-nested/output-max b/testing/btest/Baseline/spicy.file-analyzer-nested/output-max index c7a6a03585..f973bfca9d 100644 --- a/testing/btest/Baseline/spicy.file-analyzer-nested/output-max +++ b/testing/btest/Baseline/spicy.file-analyzer-nested/output-max @@ -1,7 +1,7 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. data3, FyjjRu4ARLzpsPLhNh, data3, Fz3QLf4Bn4qaQwyUdk, -depth warning, FyjjRu4ARLzpsPLhNh, [chunk_event=, stream_event=, extract_filename=, extract_limit=0], 2 -depth warning, Fz3QLf4Bn4qaQwyUdk, [chunk_event=, stream_event=, extract_filename=, extract_limit=0], 2 +depth warning, FyjjRu4ARLzpsPLhNh, [chunk_event=, stream_event=, extract_filename=, extract_limit=0, extract_limit_includes_missing=T], 2 +depth warning, Fz3QLf4Bn4qaQwyUdk, [chunk_event=, stream_event=, extract_filename=, extract_limit=0, extract_limit_includes_missing=T], 2 data2, F2Qpmk14ATv4vFSEsi, from 1:hello world data1, FcRmxz1fPbKQEgGGUi, hello world diff --git a/testing/btest/Traces/http/http-large-gap.pcap b/testing/btest/Traces/http/http-large-gap.pcap new file mode 100644 index 0000000000..649f5305fc Binary files /dev/null and b/testing/btest/Traces/http/http-large-gap.pcap differ diff --git a/testing/btest/scripts/base/files/extract/limit-large-hole.zeek b/testing/btest/scripts/base/files/extract/limit-large-hole.zeek new file mode 100644 index 0000000000..221e91fd73 --- /dev/null +++ b/testing/btest/scripts/base/files/extract/limit-large-hole.zeek @@ -0,0 +1,38 @@ +# @TEST-EXEC: zeek -C -b -r $TRACES/http/http-large-gap.pcap %INPUT efname=1 FileExtract::default_limit_includes_missing=T +# @TEST-EXEC: btest-diff --binary extract_files/1 +# @TEST-EXEC: btest-diff 1.out +# @TEST-EXEC: mv files.log files-1.log +# @TEST-EXEC: btest-diff files-1.log +# @TEST-EXEC: zeek -C -b -r $TRACES/http/http-large-gap.pcap %INPUT efname=2 FileExtract::default_limit_includes_missing=F +# @TEST-EXEC: rm extract_files/2 +# @TEST-EXEC: btest-diff 2.out +# @TEST-EXEC: mv files.log files-2.log +# @TEST-EXEC: btest-diff files-2.log +# @TEST-EXEC: zeek -C -b -r $TRACES/http/http-large-gap.pcap %INPUT efname=3 FileExtract::default_limit_includes_missing=F max_extract=1 +# @TEST-EXEC: rm extract_files/3 +# @TEST-EXEC: btest-diff 3.out +# @TEST-EXEC: mv files.log files-3.log +# @TEST-EXEC: btest-diff files-3.log + +@load base/files/extract +@load base/protocols/http + +global outfile: file; +const max_extract: count = 10 &redef; +const efname: string = "0" &redef; + +event file_new(f: fa_file) + { + Files::add_analyzer(f, Files::ANALYZER_EXTRACT, + [$extract_filename=efname, $extract_limit=max_extract]); + } + +event file_extraction_limit(f: fa_file, args: any, limit: count, len: count) + { + print outfile, "file_extraction_limit", limit, len; + } + +event zeek_init() + { + outfile = open(fmt("%s.out", efname)); + }