/src/zeek/src/analyzer/protocol/zip/ZIP.cc
Line | Count | Source |
1 | | // See the file "COPYING" in the main distribution directory for copyright. |
2 | | |
3 | | #include "zeek/analyzer/protocol/zip/ZIP.h" |
4 | | |
5 | | namespace zeek::analyzer::zip { |
6 | | |
7 | | ZIP_Analyzer::ZIP_Analyzer(Connection* conn, bool orig, Method arg_method) |
8 | 4.20k | : analyzer::tcp::TCP_SupportAnalyzer("ZIP", conn, orig) { |
9 | 4.20k | zip = nullptr; |
10 | 4.20k | zip_status = Z_OK; |
11 | 4.20k | method = arg_method; |
12 | | |
13 | 4.20k | zip = new z_stream; |
14 | 4.20k | zip->zalloc = nullptr; |
15 | 4.20k | zip->zfree = nullptr; |
16 | 4.20k | zip->opaque = nullptr; |
17 | 4.20k | zip->next_out = nullptr; |
18 | 4.20k | zip->avail_out = 0; |
19 | 4.20k | zip->next_in = nullptr; |
20 | 4.20k | zip->avail_in = 0; |
21 | | |
22 | | // "32" is a gross overload hack that means "check it |
23 | | // for whether it's a gzip file". Sheesh. |
24 | 4.20k | if ( inflateInit2(zip, MAX_WBITS + 32) != Z_OK ) { |
25 | 0 | Weird("inflate_init_failed"); |
26 | 0 | delete zip; |
27 | 0 | zip = nullptr; |
28 | 0 | } |
29 | 4.20k | } |
30 | | |
31 | 4.20k | ZIP_Analyzer::~ZIP_Analyzer() { delete zip; } |
32 | | |
33 | 4.20k | void ZIP_Analyzer::Done() { |
34 | 4.20k | Analyzer::Done(); |
35 | | |
36 | 4.20k | if ( zip ) |
37 | 4.20k | inflateEnd(zip); |
38 | 4.20k | } |
39 | | |
40 | 12.5k | void ZIP_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { |
41 | 12.5k | analyzer::tcp::TCP_SupportAnalyzer::DeliverStream(len, data, orig); |
42 | | |
43 | 12.5k | if ( ! len || zip_status != Z_OK ) |
44 | 5.92k | return; |
45 | | |
46 | 6.67k | static unsigned int unzip_size = 4096; |
47 | 6.67k | auto unzipbuf = std::make_unique<Bytef[]>(unzip_size); |
48 | | |
49 | 6.67k | int allow_restart = 1; |
50 | | |
51 | 6.67k | zip->next_in = reinterpret_cast<Bytef*>(const_cast<u_char*>(data)); |
52 | 6.67k | zip->avail_in = len; |
53 | | |
54 | 6.67k | auto orig_next_in = zip->next_in; |
55 | 6.67k | size_t orig_avail_in = zip->avail_in; |
56 | | |
57 | 11.9k | while ( true ) { |
58 | 11.9k | zip->next_out = unzipbuf.get(); |
59 | 11.9k | zip->avail_out = unzip_size; |
60 | | |
61 | 11.9k | zip_status = inflate(zip, Z_SYNC_FLUSH); |
62 | | |
63 | 11.9k | if ( zip_status == Z_STREAM_END || zip_status == Z_OK ) { |
64 | 3.79k | allow_restart = 0; |
65 | | |
66 | 3.79k | int have = unzip_size - zip->avail_out; |
67 | 3.79k | if ( have ) |
68 | 2.99k | ForwardStream(have, unzipbuf.get(), IsOrig()); |
69 | | |
70 | 3.79k | if ( zip_status == Z_STREAM_END ) { |
71 | 274 | inflateEnd(zip); |
72 | 274 | return; |
73 | 274 | } |
74 | | |
75 | 3.52k | if ( zip->avail_in == 0 ) |
76 | 2.93k | return; |
77 | 3.52k | } |
78 | | |
79 | 8.10k | else if ( allow_restart && zip_status == Z_DATA_ERROR ) { |
80 | | // Some servers seem to not generate zlib headers, |
81 | | // so this is an attempt to fix and continue anyway. |
82 | 4.63k | inflateEnd(zip); |
83 | | |
84 | 4.63k | if ( inflateInit2(zip, -MAX_WBITS) != Z_OK ) { |
85 | 0 | Weird("inflate_init_failed"); |
86 | 0 | return; |
87 | 0 | } |
88 | | |
89 | 4.63k | zip->next_in = orig_next_in; |
90 | 4.63k | zip->avail_in = orig_avail_in; |
91 | 4.63k | allow_restart = 0; |
92 | 4.63k | continue; |
93 | 4.63k | } |
94 | | |
95 | 3.47k | else { |
96 | 3.47k | Weird("inflate_failed"); |
97 | 3.47k | return; |
98 | 3.47k | } |
99 | 11.9k | } |
100 | 6.67k | } |
101 | | |
102 | | } // namespace zeek::analyzer::zip |