1 |
// Copyright (C) 2003, 2004 Stephane Thiell |
2 |
// |
3 |
// This file is part of pxyscand (from pxys) |
4 |
// |
5 |
// This program is free software; you can redistribute it and/or |
6 |
// modify it under the terms of the GNU General Public License |
7 |
// as published by the Free Software Foundation; either version 2 |
8 |
// of the License, or (at your option) any later version. |
9 |
// |
10 |
// This program is distributed in the hope that it will be useful, |
11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
// GNU General Public License for more details. |
14 |
// |
15 |
// You should have received a copy of the GNU General Public License |
16 |
// along with this program; if not, write to the Free Software |
17 |
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
// |
19 |
#define RCSID "$Id: PXScan.cc,v 1.5 2004/01/10 14:32:29 mbuna Exp $" |
20 |
|
21 |
#define SCAN_TIMING 1.0 |
22 |
|
23 |
#include "PXScan.h" |
24 |
#include "PXScanManager.h" |
25 |
#include "PXSession.h" |
26 |
|
27 |
/* Module headers */ |
28 |
#include "PXMWingate.h" |
29 |
#include "PXMSocks.h" |
30 |
#include "PXMHttpProxy.h" |
31 |
#include "PXMCrazyBandit.h" |
32 |
|
33 |
#include <algorithm> |
34 |
#include <cassert> |
35 |
#include <peak/peak.h> |
36 |
|
37 |
bool PXScan::sInitialized = false; |
38 |
|
39 |
PXScan::PXScan(const opas_msg_query &inQuery, PXSession *inSession, |
40 |
PXScanManager *inScanManager) |
41 |
: mScanManager( inScanManager ), mStatus(0), mScanFlags(0) |
42 |
{ |
43 |
size_t nmods = mScanManager->mConfig->scanner.modules.size(); |
44 |
|
45 |
// Optimize memory allocation. |
46 |
mModules.reserve(nmods); |
47 |
|
48 |
// Instantiate and register our scan modules |
49 |
for (size_t i = 0; i < nmods; i++) |
50 |
{ |
51 |
PXConfigModule *mod = &mScanManager->mConfig->scanner.modules[i]; |
52 |
switch (mod->id) |
53 |
{ |
54 |
case CONFIG_MODULE_HTTP: |
55 |
this->RegisterModule(new PXMHttpProxy(this, mod->port)); |
56 |
break; |
57 |
case CONFIG_MODULE_WINGATE: |
58 |
this->RegisterModule(new PXMWingate(this)); |
59 |
break; |
60 |
case CONFIG_MODULE_SOCKS: |
61 |
this->RegisterModule(new PXMSocks(this)); |
62 |
break; |
63 |
case CONFIG_MODULE_CRAZYBANDIT: |
64 |
this->RegisterModule(new PXMCrazyBandit(this)); |
65 |
break; |
66 |
default: |
67 |
abort(); |
68 |
} |
69 |
} |
70 |
|
71 |
if (sInitialized) |
72 |
{ |
73 |
// Shuffle scans order; an idea of Jeb. |
74 |
std::random_shuffle(mModules.begin(), mModules.end()); |
75 |
} |
76 |
else |
77 |
{ |
78 |
sInitialized = true; |
79 |
this->InitModules(); |
80 |
} |
81 |
|
82 |
// And now store our first query for this scan. |
83 |
this->AppendQuery(inQuery, inSession); |
84 |
} |
85 |
|
86 |
PXScan::~PXScan() |
87 |
{ |
88 |
assert(mScanTimer == NULL); |
89 |
|
90 |
mScanManager->ScanCompleted(this); |
91 |
|
92 |
// Free resources allocated by the scan modules. |
93 |
for (int i = mModules.size(); i--; ) |
94 |
delete mModules[i]; |
95 |
} |
96 |
|
97 |
void |
98 |
PXScan::RegisterModule(PXScanModule *inScanModule) |
99 |
{ |
100 |
/* We store instantiated modules in a vector. */ |
101 |
mModules.push_back(inScanModule); |
102 |
} |
103 |
|
104 |
void |
105 |
PXScan::InitModules() |
106 |
{ |
107 |
for (size_t i = 0; i < mModules.size(); i++) |
108 |
mModules[i]->InitModule(); |
109 |
} |
110 |
|
111 |
void |
112 |
PXScan::SneakModule(const char *inShortName, uint16_t inPort, |
113 |
uint32_t *inConnCountPtr, uint32_t *inProxyCountPtr) const |
114 |
{ |
115 |
mScanManager->UseModule(new PXModuleInfo(inShortName, |
116 |
inPort, |
117 |
inConnCountPtr, |
118 |
inProxyCountPtr)); |
119 |
} |
120 |
|
121 |
void |
122 |
PXScan::AppendQuery(const opas_msg_query &inQuery, PXSession *inSession) |
123 |
{ |
124 |
PXScanQuery query = { inQuery, inSession }; |
125 |
mScanQueryList.push_back(query); |
126 |
} |
127 |
|
128 |
bool |
129 |
PXScan::IsSessionReferenced(const PXSession *inSession) |
130 |
{ |
131 |
list<PXScanQuery>::const_iterator i = mScanQueryList.begin(); |
132 |
for (; i != mScanQueryList.end(); i++) |
133 |
if ((*i).session == inSession) |
134 |
return true; |
135 |
return false; |
136 |
} |
137 |
|
138 |
void |
139 |
PXScan::Schedule() |
140 |
{ |
141 |
if (!mScanManager->AddScan(this)) |
142 |
{ |
143 |
this->Error(1000); |
144 |
this->Done(); |
145 |
} |
146 |
} |
147 |
|
148 |
void |
149 |
PXScan::Start() |
150 |
{ |
151 |
// Sanity check, no module is no fun. |
152 |
assert(mModules.size() > 0); |
153 |
|
154 |
// Initialize stuffs. Iterator points to first module. |
155 |
mModuleIterator = mModules.begin(); |
156 |
mCompletedCount = 0; |
157 |
mCompletedMax = mModules.size(); |
158 |
mLaunched = 0; |
159 |
mStatus = PXSCAN_SCANNING; |
160 |
|
161 |
// Prepare for next scan, with a little delay |
162 |
// |
163 |
mScanTimer = peak_timer_create(SCAN_TIMING, SCAN_TIMING, // repeat! |
164 |
TimerCallback, this); |
165 |
if (!mScanTimer) |
166 |
abort(); |
167 |
|
168 |
peak_task_timer_add(peak_task_self(), mScanTimer); |
169 |
peak_release(mScanTimer); |
170 |
|
171 |
// Launch first scan type. |
172 |
this->Launch(); |
173 |
} |
174 |
|
175 |
void |
176 |
PXScan::Launch() |
177 |
{ |
178 |
if (mModuleIterator == mModules.end()) |
179 |
{ |
180 |
// All scan types are now launched. |
181 |
mMutex.Lock(); |
182 |
this->TimerStop(); |
183 |
mMutex.Unlock(); |
184 |
return; |
185 |
} |
186 |
|
187 |
mMutex.Lock(); |
188 |
if (mStatus == PXSCAN_SCANNING) |
189 |
{ |
190 |
// Normal way. |
191 |
mLaunched++; |
192 |
mMutex.Unlock(); |
193 |
|
194 |
if (!(*mModuleIterator)->StartScan()) |
195 |
{ |
196 |
this->Error(1000); |
197 |
this->Completed(*mModuleIterator); |
198 |
} |
199 |
else |
200 |
mModuleIterator++; |
201 |
} |
202 |
else |
203 |
{ |
204 |
// A proxy has already been found or an error occured. |
205 |
if (mCompletedCount == mLaunched) |
206 |
{ |
207 |
// Special case: all launched modules have been completed! |
208 |
this->TimerStop(); |
209 |
mMutex.Unlock(); |
210 |
// -serialized- |
211 |
this->Done(); // We are done. |
212 |
} |
213 |
else |
214 |
{ |
215 |
mCompletedMax = mLaunched; // Done at next module completion |
216 |
this->TimerStop(); |
217 |
mMutex.Unlock(); |
218 |
} |
219 |
} |
220 |
} |
221 |
|
222 |
void |
223 |
PXScan::Completed(PXScanModule * /* inCompletedModule */) |
224 |
{ |
225 |
mMutex.Lock(); |
226 |
assert(mCompletedCount < mCompletedMax); |
227 |
if (++mCompletedCount == mCompletedMax) |
228 |
{ |
229 |
this->TimerStop(); |
230 |
mMutex.Unlock(); |
231 |
// -serialized- |
232 |
this->Done(); // We are done. |
233 |
return; |
234 |
} |
235 |
mMutex.Unlock(); |
236 |
} |
237 |
|
238 |
void |
239 |
PXScan::Done() |
240 |
{ |
241 |
if (mStatus == PXSCAN_SCANNING) |
242 |
this->ProxyNotFound(); |
243 |
|
244 |
delete this; |
245 |
} |
246 |
|
247 |
void |
248 |
PXScan::ProxyNotFound() |
249 |
{ |
250 |
list<PXScanQuery>::iterator i = mScanQueryList.begin(); |
251 |
i->session->ScanCompletedNoProxy(i->query); |
252 |
|
253 |
for (; i != mScanQueryList.end(); i++) |
254 |
i->session->ScanResultNoProxy(i->query, false); |
255 |
} |
256 |
|
257 |
void |
258 |
PXScan::ProxyFound(uint16_t inTypeOfProxy, uint16_t inPort, |
259 |
const char *inDescr) |
260 |
{ |
261 |
mMutex.Lock(); |
262 |
if (mStatus == PXSCAN_SCANNING) |
263 |
{ |
264 |
mStatus = PXSCAN_PROXY_FOUND; |
265 |
|
266 |
list<PXScanQuery>::iterator i = mScanQueryList.begin(); |
267 |
i->session->ScanCompletedProxy(i->query, inTypeOfProxy, inPort, inDescr); |
268 |
|
269 |
for (; i != mScanQueryList.end(); i++) |
270 |
i->session->ScanResultProxy(i->query, false, peak_time(), |
271 |
inTypeOfProxy, inPort, |
272 |
inDescr); |
273 |
} |
274 |
mMutex.Unlock(); |
275 |
} |
276 |
|
277 |
void |
278 |
PXScan::Error(int error) |
279 |
{ |
280 |
mMutex.Lock(); |
281 |
if (mStatus == PXSCAN_SCANNING) |
282 |
{ |
283 |
mStatus = PXSCAN_ERROR; |
284 |
|
285 |
list<PXScanQuery>::iterator i = mScanQueryList.begin(); |
286 |
i->session->ScanCompletedWithError(i->query); |
287 |
|
288 |
for (; i != mScanQueryList.end(); i++) |
289 |
i->session->ScanResultError(i->query, error); |
290 |
} |
291 |
mMutex.Unlock(); |
292 |
} |
293 |
|
294 |
void |
295 |
PXScan::TimerStop() |
296 |
{ |
297 |
if (mScanTimer) |
298 |
{ |
299 |
peak_task_timer_remove(peak_task_self(), mScanTimer); /* auto release */ |
300 |
mScanTimer = NULL; |
301 |
} |
302 |
} |
303 |
|
304 |
void |
305 |
PXScan::TimerCallback(peak_timer ti, void *context) |
306 |
{ |
307 |
PXScan *scan = reinterpret_cast<PXScan*>(context); |
308 |
|
309 |
assert(scan->mScanTimer == NULL || ti == scan->mScanTimer); |
310 |
|
311 |
scan->Launch(); |
312 |
} |