1 |
/* Copyright (C) 2003 Stephane Thiell |
2 |
* |
3 |
* This file is part of pxyservd (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 |
*/ |
20 |
#define RCSID "$Id: PXConfigLoader.cc,v 1.3 2004/01/02 00:33:03 mbuna Exp $" |
21 |
|
22 |
#ifdef HAVE_CONFIG_H |
23 |
#include "config.h" |
24 |
#endif |
25 |
|
26 |
#include "PXConfigLoader.h" |
27 |
#include "PXConfig.h" |
28 |
|
29 |
#include <iostream> |
30 |
|
31 |
#include <arpa/inet.h> |
32 |
|
33 |
// XPaths... |
34 |
|
35 |
#define XP_OPAS "/pxyscand/opas" |
36 |
#define XP_OPAS_PORT "port" |
37 |
#define XP_OPAS_BIND_ADDRESS "bind-address" |
38 |
#define XP_OPAS_PROTOCOL "protocol" |
39 |
#define XP_OPAS_ALLOW "allow" |
40 |
// TODO: deny |
41 |
#define XP_OPAS_LIMIT "limit" |
42 |
|
43 |
#define XP_SCANNER "/pxyscand/scanner" |
44 |
#define XP_SCANNER_MAXSCANS "maxscans" |
45 |
#define XP_SCANNER_MODULE_TYPE_ATTR "module/@type" |
46 |
#define XP_SCANNER_MODULE "module[@type]" |
47 |
#define XP_SCANNER_SOURCE_POOL "source-pool" |
48 |
#define XP_SCANNER_SOURCE_POOL_ADDRESS "address" |
49 |
#define XP_SCANNER_TARGET "target" |
50 |
#define XP_SCANNER_TARGET_ADDRESS "address" |
51 |
#define XP_SCANNER_TARGET_PORT "port" |
52 |
#define XP_SCANNER_TARGET_CHECK "target-check" |
53 |
#define XP_SCANNER_LOG_AGENT "log-agent" |
54 |
#define XP_SCANNER_TIMEOUT "timeout" |
55 |
#define XP_SCANNER_STRING "string" |
56 |
|
57 |
#define XP_CACHE "/pxyscand/cache" |
58 |
#define XP_CACHE_DIRECTORY "directory" |
59 |
#define XP_CACHE_EXPIRE "expire" |
60 |
#define XP_CACHE_PROXY_EXPIRE "proxy-expire" |
61 |
#define XP_CACHE_MAXIPS "maxips" |
62 |
|
63 |
#define XP_NOSCAN "/pxyscand/noscan" |
64 |
#define XP_NOSCAN_ADDRESS "address" |
65 |
|
66 |
using std::cout; |
67 |
using std::endl; |
68 |
|
69 |
PXConfigLoader::PXConfigLoader(const char *inFile) |
70 |
: PXXMLXPathLoaderImp(inFile) |
71 |
{ |
72 |
} |
73 |
|
74 |
PXConfigLoader::~PXConfigLoader() |
75 |
{ |
76 |
} |
77 |
|
78 |
|
79 |
bool |
80 |
PXConfigLoader::StringToNetworkNetmask(const char *str, |
81 |
in_addr &oNet, |
82 |
in_addr &oMask) |
83 |
{ |
84 |
char ipbuf[16]; |
85 |
size_t len, j; |
86 |
int k, dot = 0; |
87 |
char *p; |
88 |
|
89 |
if ((p = strchr(str, '/')) == NULL) |
90 |
oMask.s_addr = htonl(0xffffffff); |
91 |
else |
92 |
{ |
93 |
*p++ = '\0'; |
94 |
if (!strchr(p, '.')) |
95 |
{ |
96 |
int nbits; |
97 |
|
98 |
if ((nbits = atoi(p)) > 0 && nbits <= 32) |
99 |
oMask.s_addr = htonl(~(0xffffffff >> nbits)); |
100 |
} |
101 |
else if (inet_pton(AF_INET, p, &oNet) == -1) |
102 |
return false; |
103 |
} |
104 |
|
105 |
len = strlen(str); |
106 |
len = len < sizeof(ipbuf) ? len : sizeof(ipbuf) - 1; |
107 |
for (j = 0; j < len; j++) |
108 |
{ |
109 |
if (str[j] == '.') |
110 |
dot++; |
111 |
ipbuf[j] = str[j]; |
112 |
} |
113 |
if (dot > 4 || len >= sizeof(ipbuf) - ((3 - dot) * 2)) |
114 |
return false; |
115 |
|
116 |
for (k = 0; k < 3 - dot; k++) |
117 |
{ |
118 |
ipbuf[j++] = '.'; |
119 |
ipbuf[j++] = '0'; |
120 |
} |
121 |
|
122 |
assert(j < sizeof(ipbuf)); |
123 |
ipbuf[j] = '\0'; |
124 |
|
125 |
if (inet_pton(AF_INET, ipbuf, &oNet) == -1) |
126 |
return false; |
127 |
|
128 |
return true; |
129 |
} |
130 |
|
131 |
PXConfig * |
132 |
PXConfigLoader::Load() |
133 |
{ |
134 |
PXConfig *cfg = new PXConfig; |
135 |
try |
136 |
{ |
137 |
this->DoLoad(cfg); |
138 |
} |
139 |
catch (...) |
140 |
{ |
141 |
delete cfg; |
142 |
throw; |
143 |
} |
144 |
return cfg; |
145 |
} |
146 |
|
147 |
void |
148 |
PXConfigLoader::DoLoad(PXConfig *cfg) |
149 |
{ |
150 |
xmlXPathObjectPtr o, o2; |
151 |
|
152 |
if ((o = this->EvalUnique(XP_OPAS))) |
153 |
{ |
154 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
155 |
|
156 |
/* OPAS Port */ |
157 |
cfg->opas.port = this->GetInteger(XP_OPAS_PORT, 0, 1); |
158 |
|
159 |
/* OPAS local address (bind) */ |
160 |
this->GetAddress(XP_OPAS_BIND_ADDRESS, 0, 0, "opas/bind-address", |
161 |
&cfg->opas.local_address); |
162 |
|
163 |
/* Protocol(s) to enable (tcp, udp) */ |
164 |
o2 = this->Eval(XP_OPAS_PROTOCOL); |
165 |
if (!o2 || !o2->nodesetval->nodeNr) |
166 |
PXXMLException::Throw("Missing parameter", "opas/protocol"); |
167 |
cfg->opas.proto.reserve(o2->nodesetval->nodeNr); |
168 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
169 |
{ |
170 |
xmlChar *s; |
171 |
xmlNodePtr n; |
172 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
173 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
174 |
PXXMLException::Throw("Empty protocol, use: tcp or udp", |
175 |
"opas/protocol"); |
176 |
if (!strcmp((char *)s, "tcp")) |
177 |
cfg->opas.proto.push_back(PXOPAS_PROTO_TCP); |
178 |
else if (!strcmp((char *)s, "udp")) |
179 |
cfg->opas.proto.push_back(PXOPAS_PROTO_UDP); |
180 |
else |
181 |
{ |
182 |
xmlFree(s); |
183 |
PXXMLException::Throw("Unknown protocol (use: tcp or udp)", |
184 |
"opas/protocol"); |
185 |
} |
186 |
xmlFree(s); |
187 |
} |
188 |
xmlXPathFreeObject(o2); |
189 |
|
190 |
/* Allowed IPs */ |
191 |
o2 = this->Eval(XP_OPAS_ALLOW); |
192 |
if (!o2 || !o2->nodesetval->nodeNr) |
193 |
PXXMLException::Throw("Missing parameter", "opas/allow"); |
194 |
cfg->opas.allow.reserve(o2->nodesetval->nodeNr); |
195 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
196 |
{ |
197 |
xmlChar *s; |
198 |
xmlNodePtr n; |
199 |
in_addr addr; |
200 |
|
201 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
202 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
203 |
PXXMLException::Throw("Empty allow field", "opas/allow"); |
204 |
int res = inet_pton(AF_INET, (char *)s, &addr); |
205 |
xmlFree(s); |
206 |
if (res == -1) |
207 |
PXXMLException::Throw("Bad IP address", "opas/allow"); |
208 |
cfg->opas.allow.push_back(addr); |
209 |
} |
210 |
xmlXPathFreeObject(o2); |
211 |
|
212 |
/* OPAS limit */ |
213 |
cfg->opas.limit = this->GetInteger(XP_OPAS_LIMIT, 0, 1); |
214 |
|
215 |
xmlXPathFreeObject(o); |
216 |
} |
217 |
|
218 |
if ((o = this->EvalUnique(XP_SCANNER))) |
219 |
{ |
220 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
221 |
|
222 |
cfg->scanner.maxscans = this->GetInteger(XP_SCANNER_MAXSCANS, 0, 1); |
223 |
if (cfg->scanner.maxscans <= 0) |
224 |
cfg->scanner.maxscans = 100; // bah |
225 |
|
226 |
if (!(o2 = this->Eval(XP_SCANNER_MODULE_TYPE_ATTR))) |
227 |
PXXMLException::Throw("Missing parameter", "scanner/module"); |
228 |
else |
229 |
{ |
230 |
cfg->scanner.modules.reserve(o2->nodesetval->nodeNr); |
231 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
232 |
{ |
233 |
PXConfigModule m; |
234 |
xmlChar *s; |
235 |
xmlNodePtr n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
236 |
|
237 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
238 |
PXXMLException::Throw("Empty type attribute not allowed", |
239 |
"scanner/module"); |
240 |
|
241 |
m.port = 0; // only used for http scan module |
242 |
|
243 |
if (!xmlStrcasecmp(s, (xmlChar*)"wingate")) |
244 |
m.id = CONFIG_MODULE_WINGATE; |
245 |
else if (!xmlStrcasecmp(s, (xmlChar*)"socks")) |
246 |
m.id = CONFIG_MODULE_SOCKS; |
247 |
else if (!xmlStrcmp(s, (xmlChar*)"http")) |
248 |
{ |
249 |
m.id = CONFIG_MODULE_HTTP; |
250 |
m.port = this->GetInteger(XP_SCANNER_MODULE, i, 65536); |
251 |
// Note: port 0 not allowed for convenience. |
252 |
if (m.port <= 0 || m.port >= 65536) |
253 |
PXXMLException::Throw("Bad proxy port number", "scanner/module"); |
254 |
} |
255 |
else if (!xmlStrcasecmp(s, (xmlChar*)"crazybandit")) |
256 |
m.id = CONFIG_MODULE_CRAZYBANDIT; |
257 |
|
258 |
/* Handle new module type here. */ |
259 |
|
260 |
else |
261 |
PXXMLException::Throw("Unknown scanner/module type attribute", |
262 |
"scanner/module"); |
263 |
|
264 |
cfg->scanner.modules.push_back(m); |
265 |
} |
266 |
xmlXPathFreeObject(o2); |
267 |
} |
268 |
|
269 |
|
270 |
if ((o2 = this->Eval(XP_SCANNER_SOURCE_POOL))) |
271 |
{ |
272 |
StPXXPathContextNode cxNode(&mCx->node, o2->nodesetval->nodeTab[0]); |
273 |
|
274 |
xmlXPathObjectPtr o3 = this->Eval(XP_SCANNER_TARGET_ADDRESS); |
275 |
if (o3) |
276 |
{ |
277 |
int cnt = o3->nodesetval->nodeNr; |
278 |
cfg->scanner.source_pool.reserve(cnt); |
279 |
xmlXPathFreeObject(o3); |
280 |
for (int i = 0; i < cnt; i++) |
281 |
{ |
282 |
sockaddr_in sin; |
283 |
memset(&sin, 0, sizeof(sin)); |
284 |
sin.sin_family = AF_INET; |
285 |
sin.sin_port = htons(0); |
286 |
|
287 |
this->GetAddress(XP_SCANNER_TARGET_ADDRESS, i, 0, |
288 |
"scanner/source-pool/address", &sin.sin_addr); |
289 |
|
290 |
// Test the local address now. |
291 |
int testFD = socket(AF_INET, SOCK_STREAM, 0); |
292 |
if (testFD == -1) // doh ! |
293 |
PXXMLException::Throw("Source pool address test failed", |
294 |
"socket() failed!"); |
295 |
if (bind(testFD, (sockaddr *)&sin, sizeof(sin)) == -1) |
296 |
PXXMLException::Throw("Source pool address test failed", |
297 |
"bind() failed!"); |
298 |
close(testFD); |
299 |
cfg->scanner.source_pool.push_back(sin.sin_addr); |
300 |
} |
301 |
} |
302 |
xmlXPathFreeObject(o2); |
303 |
} |
304 |
|
305 |
if (!(o2 = this->Eval(XP_SCANNER_TARGET))) |
306 |
PXXMLException::Throw("Missing parameter", "scanner/target"); |
307 |
|
308 |
cfg->scanner.targets.reserve(o2->nodesetval->nodeNr); |
309 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
310 |
{ |
311 |
StPXXPathContextNode cxNodeTarget(&mCx->node, |
312 |
o2->nodesetval->nodeTab[i]); |
313 |
PXConfigScannerTarget target; |
314 |
|
315 |
this->GetAddress(XP_SCANNER_TARGET_ADDRESS, 0, 1, |
316 |
"scanner/target/address", &target.address); |
317 |
target.port = this->GetInteger(XP_SCANNER_TARGET_PORT, 0, 1); |
318 |
|
319 |
cfg->scanner.targets.push_back(target); |
320 |
} |
321 |
xmlXPathFreeObject(o2); |
322 |
|
323 |
cfg->scanner.target_check = (time_t)this->GetInteger( |
324 |
XP_SCANNER_TARGET_CHECK, 0, 1); |
325 |
cfg->scanner.log_agent = (char *)this->CopyString(XP_SCANNER_LOG_AGENT, |
326 |
0, 0); |
327 |
cfg->scanner.timeout = (time_t)this->GetInteger(XP_SCANNER_TIMEOUT, 0, 1); |
328 |
if (cfg->scanner.timeout <= 0) |
329 |
cfg->scanner.timeout = 30; |
330 |
|
331 |
if (!(o2 = this->Eval(XP_SCANNER_STRING))) |
332 |
PXXMLException::Throw("Missing parameter", "scanner/string"); |
333 |
|
334 |
cfg->scanner.strings.reserve(o2->nodesetval->nodeNr); |
335 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
336 |
{ |
337 |
xmlChar *s; |
338 |
xmlNodePtr n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
339 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
340 |
PXXMLException::Throw("Empty string field", "scanner/string"); |
341 |
cfg->scanner.strings.push_back((char*)s); |
342 |
} |
343 |
|
344 |
xmlXPathFreeObject(o2); |
345 |
xmlXPathFreeObject(o); |
346 |
} |
347 |
|
348 |
if ((o = this->EvalUnique(XP_CACHE))) |
349 |
{ |
350 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
351 |
|
352 |
// Cache directory |
353 |
cfg->cache.dir = (char *)this->CopyString(XP_CACHE_DIRECTORY, 0, 1); |
354 |
// Cache expire seconds |
355 |
cfg->cache.expire = this->GetInteger(XP_CACHE_EXPIRE, 0, 1); |
356 |
// Proxy cache expire seconds |
357 |
cfg->cache.proxy_expire = this->GetInteger(XP_CACHE_PROXY_EXPIRE, 0, 1); |
358 |
// Cache max IPs |
359 |
cfg->cache.maxips = this->GetInteger(XP_CACHE_MAXIPS, 0, 1); |
360 |
|
361 |
xmlXPathFreeObject(o); |
362 |
} |
363 |
|
364 |
if ((o = this->EvalUnique(XP_NOSCAN))) |
365 |
{ |
366 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
367 |
|
368 |
o2 = this->Eval(XP_NOSCAN_ADDRESS); |
369 |
if (o2) |
370 |
{ |
371 |
cfg->noscan.address.reserve(o2->nodesetval->nodeNr); |
372 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
373 |
{ |
374 |
xmlChar *s; |
375 |
xmlNodePtr n; |
376 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
377 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
378 |
PXXMLException::Throw("Empty allow field", "noscan/address"); |
379 |
|
380 |
NetworkNetmask nwnm; |
381 |
bool res = StringToNetworkNetmask((char *)s, nwnm.network, |
382 |
nwnm.netmask); |
383 |
xmlFree(s); |
384 |
if (!res) |
385 |
PXXMLException::Throw("Invalid address", "noscan/address"); |
386 |
cfg->noscan.address.push_back(nwnm); |
387 |
} |
388 |
xmlXPathFreeObject(o2); |
389 |
} |
390 |
xmlXPathFreeObject(o); |
391 |
} |
392 |
} |
393 |
|
394 |
void |
395 |
PXConfigLoader::Dump(PXConfig *cfg) |
396 |
{ |
397 |
size_t i; |
398 |
|
399 |
cout << "OPAS config" << endl; |
400 |
cout << "port: " << cfg->opas.port << endl; |
401 |
cout << "local_address: "; |
402 |
if (cfg->opas.local_address.s_addr == INADDR_ANY) |
403 |
cout << "default (any)"; |
404 |
else |
405 |
cout << inet_ntoa(cfg->opas.local_address); |
406 |
cout << endl; |
407 |
cout << "proto: "; |
408 |
for (i = 0; i < cfg->opas.proto.size(); i++) |
409 |
if (cfg->opas.proto[i] == PXOPAS_PROTO_TCP) |
410 |
cout << "tcp "; |
411 |
else |
412 |
cout << "udp"; |
413 |
cout << endl; |
414 |
|
415 |
cout << "allow: "; |
416 |
for (size_t i = 0; i < cfg->opas.allow.size(); i++) |
417 |
cout << inet_ntoa(cfg->opas.allow[i]) << " "; |
418 |
cout << endl; |
419 |
|
420 |
cout << "limit: "; |
421 |
if (cfg->opas.limit == 0) |
422 |
cout << "unlimited"; |
423 |
else |
424 |
cout << cfg->opas.limit; |
425 |
cout << endl << endl; |
426 |
|
427 |
cout << "SCANNER config" << endl; |
428 |
cout << "maxscans: " << cfg->scanner.maxscans << endl; |
429 |
if (cfg->scanner.modules.size() == 0) |
430 |
{ |
431 |
cout << "NO SCANNER MODULE ENABLED !!!" << endl; |
432 |
exit(1); |
433 |
} |
434 |
else |
435 |
{ |
436 |
cout << "Scanner modules (" << cfg->scanner.modules.size() << "):" << endl; |
437 |
for (i = 0; i < cfg->scanner.modules.size(); i++) |
438 |
{ |
439 |
cout << "id: " << cfg->scanner.modules[i].id << endl; |
440 |
if (cfg->scanner.modules[i].port > 0 && |
441 |
cfg->scanner.modules[i].port < 65536) |
442 |
cout << "port: " << cfg->scanner.modules[i].port << endl; |
443 |
else |
444 |
{ |
445 |
cout << "BAD PORT NUMBER: " << cfg->scanner.modules[i].port << endl; |
446 |
exit(1); |
447 |
} |
448 |
} |
449 |
} |
450 |
if (cfg->scanner.source_pool.size() == 0) |
451 |
cout << "No source pool." << endl; |
452 |
else |
453 |
{ |
454 |
cout << "Source pool (" << cfg->scanner.source_pool.size() << "):" << endl; |
455 |
for (i = 0; i < cfg->scanner.source_pool.size(); i++) |
456 |
cout << "address: " << inet_ntoa(cfg->scanner.source_pool[i]) << endl; |
457 |
} |
458 |
cout << "Targets (" << cfg->scanner.targets.size() << "):" << endl; |
459 |
for (i = 0; i < cfg->scanner.targets.size(); i++) |
460 |
{ |
461 |
cout << "address: " << inet_ntoa(cfg->scanner.targets[i].address); |
462 |
cout << " port: " << cfg->scanner.targets[i].port; |
463 |
cout << endl; |
464 |
} |
465 |
cout << "target_check: " << cfg->scanner.target_check << endl; |
466 |
cout << "Strings..." << endl; |
467 |
for (i = 0; i < cfg->scanner.strings.size(); i++) |
468 |
cout << "string: " << cfg->scanner.strings[i] << endl; |
469 |
|
470 |
cout << endl; |
471 |
cout << "CACHE config:" << endl; |
472 |
cout << "expire: " << cfg->cache.expire << " (seconds)" << endl; |
473 |
cout << "maxips: " << cfg->cache.maxips << endl << endl; |
474 |
|
475 |
cout << "NOSCAN config:" << endl; |
476 |
for (i = 0; i < cfg->noscan.address.size(); i++) |
477 |
{ |
478 |
cout << "noscan: " << inet_ntoa(cfg->noscan.address[i].network); |
479 |
cout << "/" << inet_ntoa(cfg->noscan.address[i].netmask) << endl; |
480 |
} |
481 |
} |