1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2013-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "trough.h"
25
26 #include <fnmatch.h>
27 #include <sys/stat.h>
28
29 #include <algorithm>
30 #include <fstream>
31
32 #include "helpers/directory.h"
33 #include "log/messages.h"
34 #include "main/snort_config.h"
35 #include "utils/util.h"
36
37 using namespace snort;
38
39 std::vector<struct Trough::PcapReadObject> Trough::pcap_object_list;
40 std::vector<std::string> Trough::pcap_queue;
41 std::string Trough::pcap_filter = "*.*cap*";
42 std::vector<std::string>::const_iterator Trough::pcap_queue_iter;
43
44 unsigned Trough::pcap_loop_count = 0;
45 std::atomic<unsigned> Trough::file_count{0};
46
add_pcaps_dir(const std::string & dirname,const std::string & filter)47 bool Trough::add_pcaps_dir(const std::string& dirname, const std::string& filter)
48 {
49 Directory pcap_dir(dirname.c_str(), filter.c_str());
50 if (pcap_dir.error_on_open())
51 {
52 ErrorMessage("Error getting pcaps under dir: %s: %s\n",
53 dirname.c_str(), get_error(pcap_dir.error_on_open()));
54 return false;
55 }
56
57 std::vector<std::string> tmp_queue;
58 const char* pcap_filename;
59 while ((pcap_filename = pcap_dir.next()))
60 tmp_queue.emplace_back(pcap_filename);
61 std::sort(tmp_queue.begin(), tmp_queue.end());
62
63 pcap_queue.reserve(pcap_queue.size() + tmp_queue.size());
64 pcap_queue.insert(pcap_queue.end(), tmp_queue.begin(), tmp_queue.end());
65
66 return true;
67 }
68
add_pcaps_list_file(const std::string & list_filename,const std::string & filter)69 bool Trough::add_pcaps_list_file(const std::string& list_filename, const std::string& filter)
70 {
71 std::ifstream pcap_list_file(list_filename);
72 if (!pcap_list_file.is_open())
73 {
74 ErrorMessage("Could not open pcap list file: %s: %s\n", list_filename.c_str(), get_error(errno));
75 return false;
76 }
77
78 std::string pcap_name;
79 while (getline(pcap_list_file, pcap_name))
80 {
81 /* Trim leading and trailing whitespace. */
82 constexpr const char* whitespace = " \f\n\r\t\v";
83 pcap_name.erase(0, pcap_name.find_first_not_of(whitespace));
84 pcap_name.erase(pcap_name.find_last_not_of(whitespace) + 1);
85
86 if (pcap_name.empty())
87 continue;
88
89 /* do a quick check to make sure file exists */
90 struct stat sb;
91 if (stat(pcap_name.c_str(), &sb) == -1)
92 {
93 ErrorMessage("Error getting stat on pcap file: %s: %s\n", pcap_name.c_str(), get_error(errno));
94 pcap_list_file.close();
95 return false;
96 }
97 if (S_ISDIR(sb.st_mode))
98 {
99 if (!add_pcaps_dir(pcap_name, filter))
100 {
101 pcap_list_file.close();
102 return false;
103 }
104 }
105 else if (S_ISREG(sb.st_mode))
106 {
107 if (filter.empty() || (fnmatch(filter.c_str(), pcap_name.c_str(), 0) == 0))
108 pcap_queue.emplace_back(pcap_name);
109 }
110 else
111 {
112 ErrorMessage("Specified entry in \'%s\' is not a regular file or directory: %s\n",
113 list_filename.c_str(), pcap_name.c_str());
114 pcap_list_file.close();
115 return false;
116 }
117 }
118 pcap_list_file.close();
119
120 return true;
121 }
122
add_pcaps_list(const std::string & list)123 bool Trough::add_pcaps_list(const std::string& list)
124 {
125 if (list.empty())
126 {
127 ErrorMessage("No pcaps specified in pcap list\n");
128 return false;
129 }
130
131 std::string pcap_name;
132 size_t i = 0;
133 size_t pos = 0;
134
135 do
136 {
137 pos = list.find(' ', i);
138 if (pos == std::string::npos)
139 pcap_name = list.substr(i);
140 else
141 {
142 pcap_name = list.substr(i, pos - i);
143 i = ++pos;
144 }
145 /* do a quick check to make sure file exists */
146 if (pcap_name != "-")
147 {
148 struct stat sb;
149 if (stat(pcap_name.c_str(), &sb) == -1)
150 {
151 ErrorMessage("Error getting stat on file: %s: %s (%d)\n",
152 pcap_name.c_str(), get_error(errno), errno);
153 return false;
154 }
155 if (!(sb.st_mode & (S_IFREG|S_IFIFO)))
156 {
157 ErrorMessage("Specified pcap is not a regular file: %s\n", pcap_name.c_str());
158 return false;
159 }
160 }
161
162 pcap_queue.emplace_back(pcap_name);
163 } while (pos != std::string::npos);
164
165 return true;
166 }
167
get_pcaps(const std::vector<struct PcapReadObject> & pol)168 bool Trough::get_pcaps(const std::vector<struct PcapReadObject> &pol)
169 {
170 for (const PcapReadObject &pro : pol)
171 {
172 switch (pro.type)
173 {
174 case SOURCE_FILE_LIST:
175 /* arg should be a file with a list of pcaps in it */
176 if (!add_pcaps_list_file(pro.arg, pro.filter))
177 return false;
178 break;
179
180 case SOURCE_LIST:
181 /* arg should be a space separated list of pcaps */
182 if (!add_pcaps_list(pro.arg))
183 return false;
184 break;
185
186 case SOURCE_DIR:
187 /* arg should be a directory name */
188 if (!add_pcaps_dir(pro.arg, pro.filter))
189 return false;
190 break;
191 }
192 }
193
194 return true;
195 }
196
add_source(SourceType type,const char * list)197 void Trough::add_source(SourceType type, const char* list)
198 {
199 PcapReadObject pro;
200
201 pro.type = type;
202 pro.arg = list;
203 pro.filter = pcap_filter;
204
205 pcap_object_list.emplace_back(pro);
206 }
207
set_filter(const char * f)208 void Trough::set_filter(const char* f)
209 {
210 if (f)
211 pcap_filter = f;
212 else
213 pcap_filter.erase();
214 }
215
setup()216 void Trough::setup()
217 {
218 if (!pcap_object_list.empty())
219 {
220 if (!get_pcaps(pcap_object_list))
221 FatalError("Error getting pcaps.\n");
222
223 if (pcap_queue.empty())
224 FatalError("No pcaps found.\n");
225
226 /* free pcap list used to get params */
227 pcap_object_list.clear();
228
229 pcap_queue_iter = pcap_queue.cbegin();
230 }
231 pcap_filter.clear();
232 }
233
cleanup()234 void Trough::cleanup()
235 {
236 /* clean up pcap queues */
237 pcap_queue.clear();
238 }
239
get_next()240 const char* Trough::get_next()
241 {
242 const char* pcap = nullptr;
243
244 if (pcap_queue.empty() || pcap_queue_iter == pcap_queue.cend())
245 return nullptr;
246
247 pcap = pcap_queue_iter->c_str();
248 ++pcap_queue_iter;
249 /* If we've reached the end, reset the iterator if we have more
250 loops to cover. */
251 if (pcap_queue_iter == pcap_queue.cend() && pcap_loop_count > 1)
252 {
253 pcap_loop_count--;
254 pcap_queue_iter = pcap_queue.cbegin();
255 }
256
257 file_count++;
258 return pcap;
259 }
260
has_next()261 bool Trough::has_next()
262 {
263 return (!pcap_queue.empty() && pcap_queue_iter != pcap_queue.cend());
264 }
265
266